2017-04-02 25 views
38

我试图实施认证的路线却发现阵营路由器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> 

但ISIT可能实现这一点的同时分组一堆路线在一起吗?


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 
} 

ISIT正确派遣在render()的行动感到不对劲。它似乎不正确componentDidMount或其他钩子?

+0

最好的,如果不使用服务器端渲染上componetWillMount做。 – mfahadi

+0

@mfahadi,感谢您的意见。我现在还没有使用SSR,但如果我想在未来使用,我是否保持渲染?另外,如果用户在'componentWillMount'中重定向,他们是否会在瞬间看到渲染输出? –

+0

我真的很抱歉,说'componentWillMount()不在SSR上调用,它是不调用的componentDidMount()'。因为在render()之前调用了componentWillMount(),所以用户不会看到任何新组件。所以它是检查的最佳地点。 – mfahadi

回答

73

您将要使用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}}} />} 
    /> 
) 
} 

Route S能是这个样子

<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

+1

哦,这个与我的解决方案类似,但它使用''。问题是''在我的情况下似乎不起作用?我需要发送一个动作 –

+0

我不知道为什么,但添加了'state:{from:props.location}}}'导致了'最大调用堆栈超出'。我不得不删除它。你能解释为什么这个选项很有用@Tyler McGinnis? – KeitIG

+0

@KeitIG这很奇怪。这很有用,因为它告诉你你来自哪里。例如,如果您希望用户在进行身份验证后要进行身份验证,请在将它们重定向之前将它们回到他们尝试访问的页面。 –

1

看来你的犹豫是创造你自己的组件,然后调度渲染方法?那么你可以避免使用<Route>组件的render方法。除非您确实需要,否则无需创建<AuthenticatedRoute>组件。它可以像下面这样简单。请注意0​​传播,确保您继续将<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 
8

Tnx泰勒麦金尼斯为解决方案。 我从泰勒麦金尼斯的想法让我的想法。

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" /> 
3

安装功能反应路由器-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; 
1

我知道它已经有一段时间,但我一直在努力的npm package私人和公共路线。

下面是如何使一个私人路线:

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

而且你还可以只unauthed用户可以访问

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

我希望它可以帮助公共路线!

0

我实现using-

<Route path='/dashboard' render={() => (
    this.state.user.isLoggedIn ? 
    (<Dashboard authenticate={this.authenticate} user={this.state.user} />) : 
    (<Redirect to="/login" />) 
)} /> 

身份验证的道具将被传递到组件例如使用哪种用户状态进行注册可以更改。完成AppRoutes-

import React from 'react'; 
import { Switch, Route } from 'react-router-dom'; 
import { Redirect } from 'react-router'; 

import Home from '../pages/home'; 
import Login from '../pages/login'; 
import Signup from '../pages/signup'; 
import Dashboard from '../pages/dashboard'; 

import { config } from '../utils/Config'; 

export default class AppRoutes extends React.Component { 

    constructor(props) { 
     super(props); 

     // initially assuming that user is logged out 
     let user = { 
      isLoggedIn: false 
     } 

     // if user is logged in, his details can be found from local storage 
     try { 
      let userJsonString = localStorage.getItem(config.localStorageKey); 
      if (userJsonString) { 
       user = JSON.parse(userJsonString); 
      } 
     } catch (exception) { 
     } 

     // updating the state 
     this.state = { 
      user: user 
     }; 

     this.authenticate = this.authenticate.bind(this); 
    } 

    // this function is called on login/logout 
    authenticate(user) { 
     this.setState({ 
      user: user 
     }); 

     // updating user's details 
     localStorage.setItem(config.localStorageKey, JSON.stringify(user)); 
    } 

    render() { 
     return (
      <Switch> 
       <Route exact path='/' component={Home} /> 
       <Route exact path='/login' render={() => <Login authenticate={this.authenticate} />} /> 
       <Route exact path='/signup' render={() => <Signup authenticate={this.authenticate} />} /> 
       <Route path='/dashboard' render={() => (
        this.state.user.isLoggedIn ? 
          (<Dashboard authenticate={this.authenticate} user={this.state.user} />) : 
          (<Redirect to="/login" />) 
       )} /> 
      </Switch> 
     ); 
    } 
} 

检查这里的完整的项目:https://github.com/varunon9/hello-react

相关问题