Как реализовать проверку подлинности маршруты в маршрутизаторе реагируют 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) docs, это предполагает что-то вроде
<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>
но это возможно чтобы достичь этого, группируя кучу маршрутов вместе?
обновление
ОК, после некоторых исследований, я придумал это:
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
или какой-то другой крюк либо?
9 ответов:
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" />
установить react-router-dom
затем создайте два компонента один для допустимых пользователей, а другой для недопустимых пользователей.
попробуйте это приложение.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;
кажется, ваша нерешительность заключается в создании собственного компонента, а затем диспетчеризации в методе рендеринга? Ну вы можете избежать обоих, просто используя
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} /> } />
посмотреть реагировать Маршрутизатор документации В4 оказать
если вы действительно хотите создать выделенный компонент, то, похоже, вы на правильном пути. Так как React Router V4-это чисто декларативная маршрутизация (он говорит так прямо в описании) я не думаю, что вам сойдет с рук положить ваш код перенаправления за пределами нормального жизненного цикла компонента. Глядя на код для самого маршрутизатора React, они выполняют перенаправление в любом
componentWillMount
илиcomponentDidMount
в зависимости от того, является ли рендеринг на стороне сервера. Вот код ниже, который довольно прост и может помочь вам чувствовать себя более комфортно с тем, где разместить логику перенаправления.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
Я знаю, что это было некоторое время, но я работал над 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"/>
Я надеюсь, что это помогает!
на основе ответа @Tyler McGinnis. Я сделал другой подход, используя синтаксис ES6 и вложенные маршруты С обернутой компоненты:
import React, { cloneElement, Children } from 'react' import { Route, Redirect } from 'react-router-dom' const PrivateRoute = ({ children, authed, ...rest }) => <Route {...rest} render={(props) => authed ? <div> {Children.map(children, child => cloneElement(child, { ...child.props }))} </div> : <Redirect to={{ pathname: '/', state: { from: props.location } }} />} /> export default PrivateRoute
и, используя это:
<BrowserRouter> <div> <PrivateRoute path='/home' authed={auth}> <Navigation> <Route component={Home} path="/home" /> </Navigation> </PrivateRoute> <Route exact path='/' component={PublicHomePage} /> </div> </BrowserRouter>
просто добавляя мое решение проблемы.
Я использую токены jwt для аутентификации, поэтому, если у пользователя есть этот токен, я перенаправлю их на домашнюю страницу или перенаправлю их на страницу входа по умолчанию (это маршрут '/'). Поэтому, как только пользователь вошел в систему и попытался получить доступ к url-адресу страницы входа (в моем случае '/') . Я перенаправлю их на дом по умолчанию ('/home').
и у моих компонентов есть HOC с именем requireAuth, чтобы проверить, является ли токен пользователя действительный.если нет, то вызовите действие signout, которое удаляет токен localhistory.
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') );
я реализовал с помощью-
<Route path='/dashboard' render={() => ( this.state.user.isLoggedIn ? (<Dashboard authenticate={this.authenticate} user={this.state.user} />) : (<Redirect to="/login" />) )} />
аутентификация реквизитов будет передана компонентам, например, регистрация, с помощью которой пользовательское состояние может быть изменено. Полные Приложения -
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
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> ) }