2017-04-02 38 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

相關問題