如何在React Router 4中实现经过身份验证的路由?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在React Router 4中实现经过身份验证的路由?相关的知识,希望对你有一定的参考价值。

我试图实现经过身份验证的路由,但发现React Router 4现在阻止了它的工作:

<Route exact path="/" component={Index} />
<Route path="/auth" component={UnauthenticatedWrapper}>
    <Route path="/auth/login" component={LoginBotBot} />
</Route>
<Route path="/domains" component={AuthenticatedWrapper}>
    <Route exact path="/domains" component={DomainsIndex} />
</Route>

错误是:

警告:你不应该在同一条路线上使用<Route component><Route children>; <Route children>将被忽略

在这种情况下,有什么正确的方法来实现这个?

它出现在react-router(v4)文档中,它表明类似的东西

<Router>
    <div>
    <AuthButton/>
    <ul>
        <li><Link to="/public">Public Page</Link></li>
        <li><Link to="/protected">Protected Page</Link></li>
    </ul>
    <Route path="/public" component={Public}/>
    <Route path="/login" component={Login}/>
    <PrivateRoute path="/protected" component={Protected}/>
    </div>
</Router>

但是,将一堆路线组合在一起是否有可能实现这一目标?


UPDATE

好的,经过一些研究,我想出了这个:

import React, {PropTypes} from "react"
import {Route} from "react-router-dom"

export default class AuthenticatedRoute extends React.Component {
  render() {
    if (!this.props.isLoggedIn) {
      this.props.redirectToLogin()
      return null
    }
    return <Route {...this.props} />
  }
}

AuthenticatedRoute.propTypes = {
  isLoggedIn: PropTypes.bool.isRequired,
  component: PropTypes.element,
  redirectToLogin: PropTypes.func.isRequired
}

如果在render()发送一个动作是正确的,那感觉就错了。用componentDidMount或其他一些钩子看起来不是很正确吗?

答案

您将要使用Redirect组件。这个问题有几种不同的方法。这是我喜欢的一个,有一个PrivateRoute组件,它接受一个authed道具,然后根据该道具渲染。

function PrivateRoute ({component: Component, authed, ...rest}) {
  return (
    <Route
      {...rest}
      render={(props) => authed === true
        ? <Component {...props} />
        : <Redirect to={{pathname: '/login', state: {from: props.location}}} />}
    />
  )
}

现在你的Routes看起来像这样

<Route path='/' exact component={Home} />
<Route path='/login' component={Login} />
<Route path='/register' component={Register} />
<PrivateRoute authed={this.state.authed} path='/dashboard' component={Dashboard} />

如果你仍然感到困惑,我写了这篇可能有帮助的帖子 - Protected routes and authentication with React Router v4

另一答案
const Root = ({ session }) => {
  const isLoggedIn = session && session.getCurrentUser
  return (
    <Router>
      {!isLoggedIn ? (
        <Switch>
          <Route path="/signin" component={<Signin />} />
          <Redirect to="/signin" />
        </Switch>
      ) : (
        <Switch>
          <Route path="/" exact component={Home} />
          <Route path="/about" component={About} />
          <Route path="/something-else" component={SomethingElse} />
          <Redirect to="/" />
        </Switch>
      )}
    </Router>
  )
}
另一答案

Tnx Tyler McGinnis寻求解决方案。我从Tyler McGinnis的想法中提出我的想法。

const DecisionRoute = ({ trueComponent, falseComponent, decisionFunc, ...rest }) => {
  return (
    <Route
      {...rest}

      render={
        decisionFunc()
          ? trueComponent
          : falseComponent
      }
    />
  )
}

你可以这样实现

<DecisionRoute path="/signin" exact={true}
            trueComponent={redirectStart}
            falseComponent={SignInPage}
            decisionFunc={isAuth}
          />

decisionFunc只是一个返回true或false的函数

const redirectStart = props => <Redirect to="/orders" />
另一答案

安装react-router-dom

然后为有效用户创建两个组件,为无效用户创建另一个组件。

在app.js上试试这个

import React from 'react';

import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect
} from 'react-router-dom';

import ValidUser from "./pages/validUser/validUser";
import InValidUser from "./pages/invalidUser/invalidUser";
const loggedin = false;

class App extends React.Component {
 render() {
    return ( 
      <Router>
      <div>
        <Route exact path="/" render={() =>(
          loggedin ? ( <Route  component={ValidUser} />)
          : (<Route component={InValidUser} />)
        )} />

        </div>
      </Router>
    )
  }
}
export default App;
另一答案

我知道已经有一段时间了,但我一直在为私人和公共路线制作npm package

以下是如何制作私人路线:

<PrivateRoute exact path="/private" authed={true} redirectTo="/login" component={Title} text="This is a private route"/>

您还可以创建只有未经过通信的用户才能访问的公共路由

<PublicRoute exact path="/public" authed={false} redirectTo="/admin" component={Title} text="This route is for unauthed users"/>

我希望它有所帮助!

另一答案

只需添加我的问题解决方案。

我正在使用jwt令牌进行身份验证,所以如果用户有该令牌,那么我会将它们重定向到主页,否则我会将它们重定向到默认的登录页面(这是这条路线'/')。因此,一旦用户登录并尝试访问登录页面URL(在我的情况下为'/')。我会默认将它们重定向到家('/ home')。

我的组件确实有名为requireAuth的HOC来检查用户令牌是否有效。如果没有,则调用注销操作,删除本地历史令牌。

import React, { Component, Fragment } from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch, Redirect  } from 'react-router-dom';  

//and also import appropriate components

//middleware

  class checkStatus extends React.Component {
        render() {
              if(localStorage.getItem('token')){
                return (
                  <Fragment>
                    <App>
                      <Route path="/home" exact component={Overview} />
                      <Route path="/home/add" exact component={Add} />
                      <Route path="/signout" component={Signout} />
                      <Route path="/details" component={details} />
                      <Route exact path="/" render={() => <Redirect to="/home" />} />
                    </App>

                </Fragment>
                )
              }else{
                return (
                  <Fragment>
                    <Route path="/" exact component={Signin} />
                    <Redirect to="/"  />
                  </Fragment>
                )
              }
         } }

    ReactDOM.render(   <Provider store={store}>
        <BrowserRouter>
          <Switch >
              <Route path="/" exact component={checkStatus} />
              <Route path="/:someParam"  component={checkStatus}/>
          </Switch >
        </BrowserRouter>   </Provider>,   document.querySelector('#root')
);
另一答案

您似乎犹豫是在创建自己的组件,然后在render方法中调度?那么你可以通过使用render组件的<Route>方法来避免这两种情况。除非你真的想要,否则无需创建<AuthenticatedRoute>组件。它可以像下面一样简单。请注意{...routeProps}传播,确保继续将<Route>组件的属性发送到子组件(在本例中为<MyComponent>)。

<Route path='/someprivatepath' render={routeProps => {

   if (!this.props.isLoggedIn) {
      this.props.redirectToLogin()
      return null
    }
    return <MyComponent {...routeProps} anotherProp={somevalue} />

} />

React Router V4 render documentation

如果你确实想要创建一个专用组件,那么看起来你是在正确的轨道上。由于React Router V4是纯粹的声明性路由(它在描述中如此说明),我认为你不会放弃将重定向代码放在正常的组件生命周期之外。看看code for React Router itself,他们在componentWillMountcomponentDidMount中执行重定向,具体取决于它是否是服务器端渲染。以下是下面的代码,它非常简单,可以帮助您更轻松地放置重定向逻辑。

import React, { PropTypes } from 'react'

/**
 * The public API for updating the location programatically
 * with a component.
 */
class Redirect extends React.Component {
  static propTypes = {
    push: PropTypes.bool,
    from: PropTypes.string,
    to: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.object
    ])
  }

  static defaultProps = {
    push: false
  }

  static contextTypes = {
    router: PropTypes.shape({
      history: PropTypes.shape({
        push: PropTypes.func.isRequired,
        replace: PropTypes.func.isRequired
      }).isRequired,
      staticContext: PropTypes.object
    }).isRequired
  }

  isStatic() {
    return this.context.router && this.context.router.staticContext
  }

  componentWillMount() {
    if (this.isStatic())
      this.perform()
  }

  componentDidMount() {
    if (!this.isStatic())
      this.perform()
  }

  perform() {
    const { history } = this.context.router
    const { push, to } = this.props

    if (push) {
      history.push(to)
    } else {
      history.replace(to)
    }
  }

  render() {
    return null
  }
}

export default Redirect
另一答案

根据以上是关于如何在React Router 4中实现经过身份验证的路由?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 React/Express 应用程序中实现可选身份验证?

在 Typescript 项目中实现 react-router PrivateRoute

如何使用 rnfirebase 动态链接和身份验证模块 v6 在 React Native 中实现 signInWithEmailLink

React Router V4 使用 Material UI 在 ListItem 中实现 NavLink

受保护的路由 React Router 4 无法使用存储在 Redux 中的身份验证状态

如何在 ASP.NET MVC 中实现自定义主体和身份?