You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

路由跳转前验证Token:异步请求导致页面无法正常跳转的解决

我的React路由鉴权问题及解决方案

问题背景

我本来以为这是个简单问题,但对异步/回调逻辑不太熟悉。我写了PrivateRoute组件来保护后台资源,防止未认证用户直接访问。最开始只检查本地存储里的token,正常情况下能跳转到资源页,但没法处理token过期的情况——用户本地存着过期token,系统还是会让他进资源页,这显然不安全。所以我想在跳转前先调用后端接口验证token的有效性。

遇到的问题

axios请求能正确返回结果,console.log也显示then块执行了,但已认证用户就是没法跳转到对应资源页,页面一直停留在登录页。

原App.js代码

const PrivateRoute = ({component: Component, isAuthorized, ...otherProps}) => ( 
  <Route {...otherProps} render={props => ( 
    isAuthorized() ? (<Component {...props} />) : ( 
      <Redirect to={ { pathname: '/', state: {from: props.location}, } } /> 
    ) 
  )} /> 
);
function verifyToken(isAuthenticated){ 
  if (isAuthenticated) { 
    axios.post(`${BACKEND_URL}/api-token-verify/`, { token: getAuthToken() })
    .then((res) => { 
      console.log('then'); 
      return true; 
    }) 
    .catch((err) => { 
      console.log('err'); 
      return false; 
    }); 
  } else { 
    console.log('ahaha'); 
    return false; 
  } 
}
// Deal with an ordinary outdated token. Hacked one will be handle on individual component
function hasToken() { 
  const token = localStorage.getItem('authToken'); 
  const isAuthenticated = !((token === undefined) | (token === null)); 
  return verifyToken(isAuthenticated); 
}
class App extends Component { 
  render() { 
    return ( 
      <Provider store={store}> 
        <BrowserRouter> 
          <Switch> 
            <Route exact path='/' component={Login}/> 
            <PrivateRoute exact path='/simulator/' isAuthorized={hasToken} component={Simulator}/> 
          </Switch> 
        </BrowserRouter> 
      </Provider> 
    ) 
  } 
}
export default App;

我想知道怎么才能让异步验证的流程按预期顺序执行?

解决方案

感谢m0meni的回答和评论帮我搞定了这个问题。我基于他的方案修改了代码,因为没法在顶层App组件里直接用Redux处理异步逻辑,所以新建了Container组件来托管所有路由和鉴权逻辑。

修改后的App.js

class App extends Component { 
  render() { 
    return ( 
      <Provider store={store}> 
        <Container/> 
      </Provider> 
    ) 
  } 
}

Container.js代码

import React, {Component, Fragment} from 'react';
import {BrowserRouter, Redirect, Route, Switch} from 'react-router-dom';
import Simulator from "../../simulators/components/Simulators";
import Login from "../../frontpage/components/login";
import {connect} from 'react-redux';
import {CHECK_TOKEN} from "../../constants";

const PrivateRoute = ({component: Component, isAuthorized, ...otherProps}) => ( 
  <Route {...otherProps} render={props => ( 
    isAuthorized() ? (<Component {...props} />) : ( 
      <Redirect to={ { pathname: '/', state: {from: props.location}, } } /> 
    ) 
  )} /> 
);

// Deal with an ordinary outdated token. Hacked one will be handle on individual component
function hasToken() { 
  const token = localStorage.getItem('authToken'); 
  return !((token === undefined) | (token === null)); 
}

class Container extends Component {
  /*
  * 为了处理Redux相关逻辑,同时不打乱顶层App组件的结构,我新建了Container组件来统管所有内容
  *
  */
  constructor(props) { 
    super(props); 
    this.props.validateToken(); 
  }
  render() { 
    console.log(this.props); 
    const {isAuthenticated, wrapper} = this.props; 
    console.log(typeof this.props.wrapper); 
    if((typeof this.props.wrapper) === 'function') { 
      console.log('this is function'); 
      return ( 
        <Fragment> 
          <BrowserRouter> 
            <Switch> 
              <Route exact path='/' component={Login}/> 
              <PrivateRoute exact path='/simulator/' isAuthorized={this.props.wrapper} component={Simulator}/> 
            </Switch> 
          </BrowserRouter> 
        </Fragment> 
      ) 
    }else{ 
      console.log('wrapper is not a function'); 
      console.log(typeof this.props.wrapper); 
      return null; 
    } 
  }
}

const mapStateToProps = ({verifyTokenReducer}, ownProps) => { return verifyTokenReducer };
const validateToken = () => { return { type: CHECK_TOKEN, payload: undefined } };
export default connect(mapStateToProps, {validateToken})(Container);

reducers.js代码

import {GOOD_TOKEN, INVALID_TOKEN} from "../constants";

function immediateReturnTrue(){ return true; }
function immediateReturnFalse(){ return false; }

export const VerifyTokenReducer = (state = {}, action) => { 
  switch (action.type) { 
    case GOOD_TOKEN: 
      return { isAuthenticated: true, wrapper: immediateReturnTrue }; 
    case INVALID_TOKEN: 
      return { isAuthenticated: false, wrapper: immediateReturnFalse }; 
    default: 
      return state; 
  } 
};

内容的提问来源于stack exchange,提问作者joe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:44:42