如何限制对react-router中路由的访问?

时间:2015-06-27 03:14:07

标签: javascript reactjs react-router

有谁知道如何限制对react-router中特定路由的访问?我想在允许访问特定路由之前检查用户是否已登录。我认为这很简单,但是文档并不清楚如何去做。

这是我应该在我定义<Route>组件的地方设置的,还是我应该在组件处理程序中处理它?<​​/ p>

<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>

8 个答案:

答案 0 :(得分:58)

接受的答案是正确的,但React团队认为Mixins是有害的(https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html)。

如果有人遇到这个问题并且正在寻找推荐的方法,我建议使用高阶组件而不是Mixins。

以下是HOC的示例,该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"/>

我在此处详细介绍了这个以及其他一些主题 - http://serverless-stack.com/chapters/create-a-hoc-that-checks-auth.html

答案 1 :(得分:23)

在React Router 4的Redirect

文档中有(现在?)这样的示例
TemplateSelector

答案 2 :(得分:2)

如果要在整个应用程序中使用身份验证,则需要在应用程序范围内存储一些数据(例如令牌)。您可以设置两个负责管理$auth对象的React mixin。这个对象不应该在这两个mixin之外可用。这是一个例子:

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使用react-router API(willTransitionTotransition.abort())。

答案 3 :(得分:1)

react-router鼓励为您的路由器采用声明式方法,您应该尽可能使路由器变得愚蠢,并避免将路由逻辑放在组件中。

以下是如何做到这一点(假设你将loggedIn道具传递给它):

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} />
];

答案 4 :(得分:0)

private-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/

答案 5 :(得分:0)

您可以使用HOC,并且auth是一个变量,您可以更改值true或false表示(授权)

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

答案 6 :(得分:0)

您可以避免在确认身份验证之前渲染组件,如下所示:

import { useState, useEffect, useRef } from 'react';
import { useHistory } from 'react-router-dom';

const Route = () => {
    const [loading, sertLoading] = useState(true);
    const history = useHistory();

    const ref = useRef<Function>({});

    // must use ref!
    ref.current.routeGuard = () => {
        const authenticationHandler = (): boolean => {
         // do authentication here
        }
        sertLoading(true);
        const go = authenticationHandler();
        if (go === false) {
            history.goBack();
        }
        sertLoading(false);
    } 

    useEffect(() => {
        ref.current.routeGuard();
        history.listen(() => {
            ref.current.routeGuard();
        });
    }, []);

    return (
        <>
            {!loading && <YourRouteComponent />}
        </>
    )
};

或者简单地说,yarn add react-routers,哪个组件有属性beforeEachbeforeRoute,就像Vue Route一样。

答案 7 :(得分:-2)

通常,登录用户将被授予令牌,并使用此令牌与服务器进行任何通信。我们通常做的是定义根页面,并在该页面之上构建。此根页面为您执行本地化,身份验证和其他配置。

这是一个例子

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或使用服务器验证令牌以查看用户是否有效登录。

希望这有助于:)