如何使用 react-router 处理身份验证?

Posted

技术标签:

【中文标题】如何使用 react-router 处理身份验证?【英文标题】:How to handle Authentication with react-router? 【发布时间】:2019-04-11 08:12:53 【问题描述】:

试图使某些路由需要身份验证。

我有这个:

class App extends Component 
  render() 
    const menuClass = `$this.props.contentMenuClass col-xs-12 col-md-9`;
    return (  
      <BrowserRouter history=browserHistory>
        <div className="App">
          <Header properties=this.props />
            <div className="container-fluid">
              <div className="row">
                <SideNav />
                <div className=menuClass id="mainContent">
                  <Switch>
                    routes.map(prop =>
                        (
                          <Route
                            path=prop.path
                            component=prop.component
                            key=prop.id
                            render=() => (
                              !AuthenticationService.IsAutheenticated() ? 
                                <Redirect to="/Login"/>
                               : 
                               <Route path=prop.path
                               component=prop.component
                               key=prop.id/>

                            )
                          />
                        ))
                  </Switch>
                </div>
              </div>
            </div>
          /* <Footer /> */

        </div>

      </BrowserRouter>
    );
  


const mapStateToProps = state => (
  contentMenuClass: state.menu,
);

export default connect(mapStateToProps)(App);

注意:是的,身份验证服务可以正常工作。

对于我正在检查用户是否经过身份验证的每条路由,如果没有,那么我想将它们重定向到登录页面,如果它们是,那么它将以“/”的路由登陆第一页。

我得到的只是:

react-dom.development.js:14227 The above error occurred in the <Route> component:
    in Route (created by App)
    in Switch (created by App)
    in div (created by App)
    in div (created by App)
    in div (created by App)
    in div (created by App)
    in Router (created by BrowserRouter)
    in BrowserRouter (created by App)
    in App (created by Connect(App))
    in Connect(App)
    in Provider

我哪里做错了?

【问题讨论】:

我会尝试首先明确添加&lt;Route path='/Login' /&gt; IsAutheenticated 的拼写很奇怪,其中有ee。对吗? 【参考方案1】:

你拼错了Autheenticated

另外,这是一个假设,因为您只提供了堆栈跟踪而不是 above error,这可能表明 AuthenticationService.IsAutheenticated 不是函数。

【讨论】:

实际上是方法本身的错误。这是一个错字,但该方法是这样调用的。【参考方案2】:

一个简单的解决方案是创建一个封装所有受保护路由的HOC(高阶组件)。

根据您的应用的嵌套程度,您可能希望使用本地状态或redux 状态。

工作示例:https://codesandbox.io/s/5m2690nn6n(使用本地状态)

routes/index.js

import React from "react";
import  BrowserRouter, Switch, Route  from "react-router-dom";
import Home from "../components/Home";
import Players from "../components/Players";
import Schedule from "../components/Schedule";
import RequireAuth from "../components/RequireAuth";

export default () => (
  <BrowserRouter>
    <RequireAuth>
      <Switch>
        <Route exact path="/" component=Home />
        <Route exact path="/players" component=Players />
        <Route path="/schedule" component=Schedule />
      </Switch>
    </RequireAuth>
  </BrowserRouter>
);

components/RequireAuth.js

import React,  Component, Fragment  from "react";
import  withRouter  from "react-router-dom";
import Login from "./Login";
import Header from "./Header";

class RequireAuth extends Component 
  state =  isAuthenticated: false ;

  componentDidMount = () => 
    if (!this.state.isAuthenticated) 
      this.props.history.push("/");
    
  ;

  componentDidUpdate = (prevProps, prevState) => 
    if (
      this.props.location.pathname !== prevProps.location.pathname &&
      !this.state.isAuthenticated
    ) 
      this.props.history.push("/");
    
  ;

  isAuthed = () => this.setState( isAuthenticated: true );

  unAuth = () => this.setState( isAuthenticated: false );

  render = () =>
    !this.state.isAuthenticated ? (
      <Login isAuthed=this.isAuthed />
    ) : (
      <Fragment>
        <Header unAuth=this.unAuth />
        this.props.children
      </Fragment>
    );


export default withRouter(RequireAuth);

或者,您可以创建一个包含受保护路由的受保护组件,而不是包装路由。

工作示例:https://codesandbox.io/s/yqo75n896x(使用 redux 而不是本地状态)。

routes/index.js

import React from "react";
import  BrowserRouter, Route, Switch  from "react-router-dom";
import  createStore  from "redux";
import  Provider  from "react-redux";
import Home from "../components/Home";
import Header from "../containers/Header";
import Info from "../components/Info";
import Sponsors from "../components/Sponsors";
import Signin from "../containers/Signin";
import RequireAuth from "../containers/RequireAuth";
import rootReducer from "../reducers";

const store = createStore(rootReducer);

export default () => (
  <Provider store=store>
    <BrowserRouter>
      <div>
        <Header />
        <Switch>
          <Route exact path="/" component=Home />
          <Route path="/info" component=Info />
          <Route path="/sponsors" component=Sponsors />
          <Route path="/protected" component=RequireAuth />
          <Route path="/signin" component=Signin />
        </Switch>
      </div>
    </BrowserRouter>
  </Provider>
);

容器/RequireAuth.js

import React from "react";
import  Route, Redirect  from "react-router-dom";
import  connect  from "react-redux";
import ShowPlayerRoster from "../components/ShowPlayerRoster";
import ShowPlayerStats from "../components/ShowPlayerStats";
import Schedule from "../components/Schedule";

const RequireAuth = ( match:  path , isAuthenticated ) =>
  !isAuthenticated ? (
    <Redirect to="/signin" />
  ) : (
    <div>
      <Route exact path=`$path/roster` component=ShowPlayerRoster />
      <Route path=`$path/roster/:id` component=ShowPlayerStats />
      <Route path=`$path/schedule` component=Schedule />
    </div>
  );

export default connect(state => (
  isAuthenticated: state.auth.isAuthenticated
))(RequireAuth);

您甚至可以通过创建包装函数来获得更多模块化。您可以通过简单地包裹组件来挑选和选择任何路线。我没有代码框示例,但它类似于 setup。

例如:&lt;Route path="/blog" component=RequireAuth(Blog) /&gt;

【讨论】:

这感觉比我尝试的要好得多。会试试的! 没想到会得到这个,但我很高兴我做到了。优秀的答案和一个很棒的活生生的例子!我确实有一个错字,但它仍然没有按我的意愿工作(在我最初的尝试中)。然而,这是一个更好的方法。谢谢!

以上是关于如何使用 react-router 处理身份验证?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Passport + Facebook + Express + create-react-app + React-Router + 代理进行身份验证

我的自定义身份验证 react-router 路由有啥问题?

MERN-stack使用react-router用户身份验证而不使用redux

使用高阶组件进行身份验证时如何延迟检查 redux 存储

如何从 express 重定向到 react-router?

如何在 React/NodeJS 身份验证流程中使用 httpOnly cookie 获取用户数据