Подтвердить что ты не робот

Как ограничить доступ к маршрутам в маршрутизаторе реакции?

Кто-нибудь знает, как ограничить доступ к определенным маршрутам в ответном маршрутизаторе? Я хочу проверить, зарегистрирован ли пользователь, прежде чем разрешить доступ к определенному маршруту. Я думал, что это будет просто, но документы не ясны, как это сделать.

Я должен это настроить, где я определяю свои компоненты <Route>, или мне нужно обрабатывать его внутри обработчиков компонентов?

<Route handler={App} path="/">
  <NotFoundRoute handler={NotFound} name="not-found"/>
  <DefaultRoute handler={Login} name="login"/>
  <Route handler={Todos} name="todos"/> {/* I want this to be restricted */}
</Route>
4b9b3361

Ответ 1

Обновление (16 августа 2019 г.)

В реакции-маршрутизаторе v4 и использовании React Hooks это выглядит немного иначе. Давайте начнем с вашего App.js.

export default function App() {
  const [isAuthenticated, userHasAuthenticated] = useState(false);

  useEffect(() => {
    onLoad();
  }, []);

  async function onLoad() {
    try {
      await Auth.currentSession();
      userHasAuthenticated(true);
    } catch (e) {
      alert(e);
    }
  }

  return (
    <div className="App container">
      <h1>Welcome to my app</h1>
      <Switch>
        <UnauthenticatedRoute
          path="/login"
          component={Login}
          appProps={{ isAuthenticated }}
        />
        <AuthenticatedRoute
          path="/todos"
          component={Todos}
          appProps={{ isAuthenticated }}
        />
        <Route component={NotFound} />
      </Switch>
    </div>
  );
}

Мы используем библиотеку Auth, чтобы проверить, аутентифицирован ли пользователь в данный момент. Замените это вашей функцией проверки подлинности. Если это так, тогда мы устанавливаем флаг isAuthenticated на true. Мы делаем это, когда наше приложение загружается впервые. Также стоит упомянуть, что вы можете добавить знак загрузки в ваше приложение во время выполнения проверки подлинности, чтобы не обновлять страницу входа при каждом обновлении страницы.

Затем мы передаем флаг нашим маршрутам. Мы создаем два типа маршрутов AuthenticatedRoute и UnauthenticatedRoute.

AuthenticatedRoute.js выглядит следующим образом.

export default function AuthenticatedRoute({ component: C, appProps, ...rest }) {
  return (
    <Route
      {...rest}
      render={props =>
        appProps.isAuthenticated
          ? <C {...props} {...appProps} />
          : <Redirect
              to={'/login?redirect=${props.location.pathname}${props.location.search}'}
            />}
    />
  );
}

Он проверяет, установлено ли isAuthenticated на true. Если это так, то он будет отображать нужный компонент. Если нет, то он будет перенаправлен на страницу входа.

UnauthenticatedRoute.js с другой стороны выглядит следующим образом.

export default ({ component: C, appProps, ...rest }) =>
  <Route
    {...rest}
    render={props =>
      !appProps.isAuthenticated
        ? <C {...props} {...appProps} />
        : <Redirect to="/" />}
  />;

В этом случае, если для isAuthenticated установлено значение false, будет отображаться нужный компонент. И если он установлен в true, он отправит вас на домашнюю страницу.

Вы можете найти подробные версии этого в нашем руководстве - https://serverless-stack.com/chapters/create-a-route-that-redirects.html.

Старая версия

Принятый ответ правильный, но миксины считаются вредными (https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html) командой React.

Если кто-то сталкивается с этим вопросом и ищет рекомендуемый способ сделать это, я бы предложил использовать компоненты высшего порядка вместо миксинов.

Вот пример HOC, который проверит, вошел ли пользователь в систему, прежде чем продолжить. И если пользователь не вошел в систему, то он перенаправит вас на страницу входа. Этот компонент принимает реквизит, называемый isLoggedIn, который в основном является флагом, который может хранить ваше приложение, чтобы обозначить, если пользователь вошел в систему.

import React from 'react';
import { withRouter } from 'react-router';

export default function requireAuth(Component) {

  class AuthenticatedComponent extends React.Component {

    componentWillMount() {
      this.checkAuth();
    }

    checkAuth() {
      if ( ! this.props.isLoggedIn) {
        const location = this.props.location;
        const redirect = location.pathname + location.search;

        this.props.router.push('/login?redirect=${redirect}');
      }
    }

    render() {
      return this.props.isLoggedIn
        ? <Component { ...this.props } />
        : null;
    }

  }

  return withRouter(AuthenticatedComponent);
}

И чтобы использовать этот HOC, просто оберните его вокруг ваших маршрутов. В случае вашего примера это будет:

<Route handler={requireAuth(Todos)} name="todos"/>

Я расскажу об этой и нескольких других темах в подробном пошаговом руководстве здесь - https://serverless-stack.com/chapters/create-a-hoc-that-checks-auth.html

Ответ 2

Есть (сейчас?) Пример этого в документах React Router 4 для Redirect

import { Route, Redirect } from 'react-router'

<Route exact path="/" render={() => (
  loggedIn ? (
    <Redirect to="/dashboard"/>
  ) : (
    <PublicHomePage/>
  )
)}/>

Ответ 3

Если вы хотите использовать аутентификацию во всем своем приложении, вам необходимо сохранить некоторые данные в масштабе всего приложения (например, токен). Вы можете настроить два React mixins, которые отвечают за управление объектом $auth. Этот объект не должен быть доступен вне этих двух микшинов. Вот пример этого:

define('userManagement', function() {
    'use strict';

    var $auth = {
        isLoggedIn: function () {
            // return something, e.g. using server-stored data
        }
    };

    return {
        Authenticator: {
           login: function(username, password) {
               // modify $auth object, or call server, or both
           }
        },

        NeedsAuthenticatedUser: {
            statics: {
                willTransitionTo: function (transition) {
                    if (!$auth.isLoggedIn()) {
                        transition.abort();
                    }
                }
            }
        }
    };
});

Затем вы можете просто микшировать Authenticator смешение с вашими компонентами входа (экран входа в систему, всплывающее окно входа и т.д.) и вызвать функцию this.login, когда у вас есть все необходимые данные.

Самое главное - защитить свои компоненты, смешав в NeedsAuthenticatedUser mixin. Каждый компонент, которому требуется аутентифицированный пользователь, должен выглядеть следующим образом:

var um = require('userManagement');

var ProtectedComponent = React.createClass({
    mixins: [um.NeedsAuthenticatedUser]
    // ...
}

Обратите внимание, что NeedsAuthenticatedUser использует API-интерфейс взаимодействия (willTransitionTo и transition.abort()).

Ответ 4

react-router поощряет декларативный подход к вашему маршрутизатору, вы должны сделать ваш маршрутизатор настолько глупым, насколько это возможно, и не ставьте свою логику маршрутизации в свои компоненты.

Вот как вы можете это сделать (предполагая, что вы передаете его loggedIn prop):

const DumbRouter = ({ loggedIn }) => (
  <Router history={history}>
    <Switch>
      {[
        !loggedIn && LoggedOutRoutes,
        loggedIn && LoggedInRouter,
        <Route component={404Route} />
      ]}
    </Switch>
  </Router>
);

const LoggedInRoutes = [
  <Route path="/" component={Profile} />
];

const LoggedOutRoutes = [
  <Route path="/" component={Login} />
];

Ответ 5

частно-route.tsx

import {Redirect, Route, RouteProps} from 'react-router';
import * as React from 'react';

interface PrivateRouteProps extends RouteProps {
  /**
   * '/login' for example.
   */
  redirectTo: string;

  /**
   * If true, won't redirect.
   * We are using a function instead of a bool, a bool does not seem to be updated
   * after having successfully authenticated.
   */
  isLogged: () => boolean;
}


export function PrivateRoute(props: PrivateRouteProps) {
  // 'component: Component' is not typing, it assign the value to a new variable.
  let { isLogged, redirectTo, component: Component, ...rest }: any = props;

  // error: JSX type element Component does not have call signature or ... AVOIDED BY ADDING ANY, still work,
  // and did not find a proper way to fix it.
  return <Route {...rest} render={(props) => (
    isLogged()
      ? <Component {...props}/>
      : <Redirect to={{
        pathname: redirectTo,
        state: { from: props.location }
      }} />
  )} />;
}

Использование:

        <PrivateRoute exact={true} 
                      path="/admin/" 
                      redirectTo={'/admin/login'} 
                      isLogged={this.loginService.isLogged} 
                      component={AdminDashboardPage}/>
        <Route path="/admin/login/" component={AdminLoginPage}/>

Основано на https://tylermcginnis.com/react-router-protected-routes-authentication/.

Ответ 6

Вы можете использовать HOC, а auth - это переменная, вы можете изменить значение true или false (авторизация)

<Route path="/login" component={SignIn} />
<Route path="/posts" render = {() => (auth ?  (<Post />) : (<Redirect to="/login" />))}/>

Ответ 7

обычно регистрируемому пользователю предоставляется токен, и он использует этот токен для любой связи с сервером. То, что мы обычно делаем, это определить корневую страницу, и все будет строиться поверх этой страницы. эта корневая страница выполняет локализацию, аутентификацию и другие конфигурации для вас.

здесь пример

Routes = (
    <Route path="/" handler={Root}>
        <Route name="login" handler={Login} />
        <Route name="forget" handler={ForgetPassword} />
        <Route handler={Main} >
            <Route name="overview" handler={Overview} />
            <Route name="profile" handler={Profile} />
            <DefaultRoute handler={Overview} />
        </Route>
        <DefaultRoute handler={Login} />
        <NotFoundRoute handler={NotFound} />
    </Route>
);

на вашей корневой странице, проверьте наличие токена null или аутентифицируйте токен с сервером, чтобы узнать, действителен ли пользователь.

надеюсь, что это поможет:)