首页 > 解决方案 > 使用 axios 异步函数验证 React 路由

问题描述

所以我正在创建一个带有服务器(节点+快递)和客户端(cra)端的网络应用程序。根据我设置为 cookie 的 jwt 令牌验证用户时遇到问题。服务器端的验证 api 端点正常工作(用邮递员测试),但问题是返回承诺的异步检查函数,因此路由并不知道它是否经过验证,因为响应处于挂起状态。

这是服务器端的 api 端点:/api/token.js

router.get('/',
    jwt({secret:'token-secret' }),
    function (req,res) {
        console.log(req);
        if(!req.user) return res.sendStatus(401);
        res.sendStatus(200);
        }
    )

这是客户端的 app.js: src/app.js 处理路由( /dashboard 应该只对经过验证的用户可用)

function App() {

    function checkToken() {
        let token = Cookies.get('Access Token')
        axios.get('http://localhost:9000/api/token', {
            headers: {
                'Authorization': `bearer ${token}`
            }
        }).then(res => {
            return res.status;
        }).catch(err => console.log(err));
    }

    const handleToken = async () => {
        const result = await checkToken();
        return result;
    }

  return (
      <BrowserRouter>
          <Route exact={true} path='/' render={() => (
              <div className="App">
                  <Home />
              </div>
          )}/>
          <Route exact={true} path='/dashboard' render={() => (
              <div className="App">
                  {console.log('checktoken log', handleToken())}
                  {checkToken() ? <Dashboard /> : <Login />}
              </div>
              )}/>
          <Route exact={true} path='/login' render={() => (
              <div className="App">
                  <Login />
              </div>
          )}/>
      </BrowserRouter>
  );
}

在这一点上,我知道也许我不应该以这种方式进行验证,因为我可能无法在渲染之前获得返回,也许它应该在生命周期钩子 componentWillMount 中完成,但我没有能够将它引入这个文件(或者一切都应该在一个完全不同的文件中完成)。

谢谢

ps 我省略了所有导入和导出默认值,因为这与这里无关

标签: javascriptreactjsauthenticationreact-routeraxios

解决方案


好吧,我已经做了一些实质性的改变。首先,为了使用 history.push 我不得不重构 BrowserRouter 部分,所以现在它看起来像这个 app.js

    render() {
        return (
            <Router history={history}>
                <Route exact path='/' component={Home} />
                <Route exact path='/dashboard'  component={Dashboard} />
                <Route exact path='/login' component={Login} />
            </Router>
        );
    }

然后我决定不使用 api/token.js。我创建了一个高阶组件,而不是这个 api 端点,它将检查登录期间设置的 cookie。给我带来最大麻烦的部分是获取 cookie 的异步特性。这是通过 getCookie 函数中的 setTimeout 解决的,我在 componentDidMount 生命周期中调用了这个函数。

src/components/withAuth.js

state = {
            data: false,
            open: false,
            auth: false
        }

        componentDidMount() {
            this.getCookie();
        }

        getCookie(){
            this.setState({
                open: true,
            })
            setTimeout(() => {
                const cookie = Cookies.get('Access Token')
                if(cookie) {
                    this.setState({
                        data: true,
                        open: false,
                        auth: true
                    })
                } else if (cookie === undefined) {
                    this.setState({
                        auth: true,
                        open: false
                    })
                }
            }, 700)
        }

最后,为了保护路由,我用 HOC src/Views/Dashboard.js 包裹了组件

import requireAuthentication from '../components/withAuth';

class Dashboard extends Component {

    render() {
        return (
            <div>
                <DashboardContent />
            </div>
        );
    }
}

export default requireAuthentication(Dashboard);

推荐阅读