当前位置: 首页 > 知识库问答 >
问题:

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

戚翼
2023-03-14

我试图实现身份验证的路由,但发现React路由器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>

错误是:

警告:您不应使用

在这种情况下,实现这一点的正确方法是什么?

它出现在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>

但是,当将一堆路线组合在一起时,有可能实现这一点吗?

经过一些研究,我得出了以下结论:

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或其他钩子,它似乎并不正确。


共有3个答案

嵇丰
2023-03-14

(使用Redux进行状态管理)

若用户试图访问任何url,首先我要检查访问令牌是否可用,若不重定向到登录页面,一旦用户使用登录页面登录,我们会将其存储在localstorage以及redux状态中。(localstorage或cookies..我们暂时将此主题与上下文无关)。
因为将状态作为已更新状态重新发布,并且将重新发布privateroutes。现在我们有了访问令牌,所以我们要重定向到主页。

将解码的授权有效载荷数据也存储在redux状态,并将其传递给响应上下文。(我们不必使用上下文,但要访问任何嵌套子组件中的授权,它可以很容易地从上下文访问,而不是将每个子组件连接到redux)...

所有不需要特殊角色的路由,登录后可以直接访问。如果它需要像管理员这样的角色(我们做了一个受保护的路由,检查他是否有想要的角色,如果不重定向到未经授权的组件)

类似地,在任何组件中,如果您必须禁用按钮或基于角色的内容。

简单地说,你可以这样做

const authorization = useContext(AuthContext);
const [hasAdminRole] = checkAuth({authorization, roleType:"admin"});
const [hasLeadRole] = checkAuth({authorization, roleType:"lead"});
<Button disable={!hasAdminRole} />Admin can access</Button>
<Button disable={!hasLeadRole || !hasAdminRole} />admin or lead can access</Button>

所以,如果用户试图插入虚拟令牌在本地存储。由于我们有访问令牌,我们将重定向到主组件。我的家庭组件将进行rest呼叫来抓取数据,由于jwt令牌是伪的,rest呼叫将返回未经授权的用户。所以我打电话注销(这将清除本地存储并重定向到登录页面)。如果主页有静态数据,并且没有进行任何api调用(那么你应该在后端有令牌验证api调用,这样你就可以在加载主页之前检查令牌是否是真实的)

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, Switch } from 'react-router-dom';
import history from './utils/history';


import Store from './statemanagement/store/configureStore';
import Privateroutes from './Privateroutes';
import Logout from './components/auth/Logout';

ReactDOM.render(
  <Store>
    <Router history={history}>
      <Switch>
        <Route path="/logout" exact component={Logout} />
        <Route path="/" exact component={Privateroutes} />
        <Route path="/:someParam" component={Privateroutes} />
      </Switch>
    </Router>
  </Store>,
  document.querySelector('#root')
);

History.js

import { createBrowserHistory as history } from 'history';

export default history({});

Privateroutes.js

import React, { Fragment, useContext } from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import { AuthContext, checkAuth } from './checkAuth';
import App from './components/App';
import Home from './components/home';
import Admin from './components/admin';
import Login from './components/auth/Login';
import Unauthorized from './components/Unauthorized ';
import Notfound from './components/404';

const ProtectedRoute = ({ component: Component, roleType, ...rest })=> { 
const authorization = useContext(AuthContext);
const [hasRequiredRole] = checkAuth({authorization, roleType});
return (
<Route
  {...rest}
  render={props => hasRequiredRole ? 
  <Component {...props} /> :
   <Unauthorized {...props} />  } 
/>)}; 

const Privateroutes = props => {
  const { accessToken, authorization } = props.authData;
  if (accessToken) {
    return (
      <Fragment>
       <AuthContext.Provider value={authorization}>
        <App>
          <Switch>
            <Route exact path="/" component={Home} />
            <Route path="/login" render={() => <Redirect to="/" />} />
            <Route exact path="/home" component={Home} />
            <ProtectedRoute
            exact
            path="/admin"
            component={Admin}
            roleType="admin"
          />
            <Route path="/404" component={Notfound} />
            <Route path="*" render={() => <Redirect to="/404" />} />
          </Switch>
        </App>
        </AuthContext.Provider>
      </Fragment>
    );
  } else {
    return (
      <Fragment>
        <Route exact path="/login" component={Login} />
        <Route exact path="*" render={() => <Redirect to="/login" />} />
      </Fragment>
    );
  }
};

// my user reducer sample
// const accessToken = localStorage.getItem('token')
//   ? JSON.parse(localStorage.getItem('token')).accessToken
//   : false;

// const initialState = {
//   accessToken: accessToken ? accessToken : null,
//   authorization: accessToken
//     ? jwtDecode(JSON.parse(localStorage.getItem('token')).accessToken)
//         .authorization
//     : null
// };

// export default function(state = initialState, action) {
// switch (action.type) {
// case actionTypes.FETCH_LOGIN_SUCCESS:
//   let token = {
//                  accessToken: action.payload.token
//               };
//   localStorage.setItem('token', JSON.stringify(token))
//   return {
//     ...state,
//     accessToken: action.payload.token,
//     authorization: jwtDecode(action.payload.token).authorization
//   };
//    default:
//         return state;
//    }
//    }

const mapStateToProps = state => {
  const { authData } = state.user;
  return {
    authData: authData
  };
};

export default connect(mapStateToProps)(Privateroutes);

checkAuth.js

import React from 'react';

export const AuthContext = React.createContext();

export const checkAuth = ({ authorization, roleType }) => {
  let hasRequiredRole = false;

  if (authorization.roles ) {
    let roles = authorization.roles.map(item =>
      item.toLowerCase()
    );

    hasRequiredRole = roles.includes(roleType);
  }

  return [hasRequiredRole];
};

解码JWT令牌样本

{
  "authorization": {
    "roles": [
      "admin",
      "operator"
    ]
  },
  "exp": 1591733170,
  "user_id": 1,
  "orig_iat": 1591646770,
  "email": "hemanthvrm@stackoverflow",
  "username": "hemanthvrm"
}
鲁景山
2023-03-14

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" />
尉迟俊能
2023-03-14

您将需要使用重定向组件。有几种不同的方法来解决这个问题。这里有一个我喜欢的,有一个私有路由组件,它接收一个编写的道具,然后根据这个道具进行渲染。

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

现在,您的路线可以如下所示

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

如果你还不明白,我写的这篇文章可能有助于使用React Router v4保护路由和身份验证

 类似资料:
  • 问题内容: 我试图实现经过身份验证的路由,但是发现React Router 4现在阻止了它的工作: 错误是: 警告:您不应使用和在同一路线上;将被忽略 在这种情况下,实现此目标的正确方法是什么? 它出现在(v4)文档中,提示类似 但是在将一堆路线组合在一起时是否有可能实现这一目标? 更新 好吧,经过一番研究,我想到了这个: 发出错误的动作是正确的感觉。似乎确实不正确,还是带有其他挂钩? 问题答案:

  • 我一直在搜索net,试图找到任何定义如何在流星和响应路由器4中处理身份验证的地方。 基本上,我希望某些路由只对经过身份验证的用户可用。有相关文件吗? 阿西尔

  • 试图使某些路由需要身份验证。 我有这个: 注意:是的,身份验证服务正常工作。 对于每个路由,我检查用户是否经过身份验证,如果没有,那么我想将他们重定向到登录页面,如果他们是,那么它将在第一个页面上着陆,路由为"/"。 我得到的只是: 我哪里做错了?

  • 根据React Router给出的示例,我正在尝试创建一个受保护的路由,当用户未被授权使用Find Router for Relay Modern时,该路由将重定向到: 我用真实的登录逻辑替换了fakeAuth,但其余的都是一样的。这条路线就是不渲染。 发现路由器似乎是轻的例子围绕这个特定的问题。有什么想法吗?

  • Flatter Web(Navigator 2.0/Router API):如何处理经过身份验证的路由及其成功身份验证后的重定向? e、 g.我的系统中有这种路由 若用户直接打开这个URL,我想让用户先登录,那个么路由将被重定向到。。 一旦登录,我想用户导航以前打开的网址,如果有任何其他主页。。 似乎这种事情可能会有所帮助,任何想法——我们如何才能实现类似的事情?https://stackover

  • 我正在react路由器v4上实现受保护的路由。我试图将“isAuthenticated”值从“Login”组件传递到“Authenticated”组件,但得到“false”值。 也许我用错了方法,任何人都可以帮助解决这个问题吗? 我的代码如下: 登录。js提供“isAuthenticated”控件 Authenticated.js需要获得“isAuthenticated”值(true)来呈现受保护