【问题标题】:Invoke logout function when route changes路由更改时调用注销功能
【发布时间】:2022-01-08 18:28:47
【问题描述】:

JWT accessToken过期后如何注销用户?

现在我使用withRouter 作为高阶组件(HOC)来检查路由变化,但它仅在用户单击浏览器的后退按钮时才有效。

我想在每次路线更改时检查路线更改,而不仅仅是返回按钮。例如,当用户点击返回主页链接时,我想检查令牌是否已过期,然后从本地存储中删除令牌。

AuthVerify.js

import React, { useEffect } from "react";
import { withRouter } from "react-router-dom";

const parseJwt = (token) => {
  try {
    return JSON.parse(atob(token.split(".")[1]));
  } catch (e) {
    return null;
  }
};

const AuthVerify = (props) => {
  console.log(props);
  useEffect(() => {
    props.history.listen(() => {
      const token = localStorage.getItem("accessToken");
      if (token) {
        const decodedJWT = parseJwt(token);

        if (decodedJWT.exp * 1000 < Date.now()) {
          console.log("expired");
          props.logOut();
        } else {
        }
      }
    });
  }, []);

  return <div></div>;
};

export default withRouter(AuthVerify);

App.js 的一部分

import { Fragment } from "react";
import { BrowserRouter, Switch, Route } from "react-router-dom";

import AuthVerify from "../src/utils/AuthVerify";

import "./App.css";

import Home from "./pages/Home";
import Signup from "../src/pages/Signup";
import Login from "../src/pages/Login";
import Test from "./pages/Test";

const logOut = () => {
  localStorage.removeItem("accessToken");
  localStorage.removeItem("refreshToken");
};

function App() {
  return (
    <Fragment>
      <div className="App">
        <BrowserRouter>
          <Switch>
            <Route exact path="/" component={Home} />
            <PrivateRoute exact path="/test" component={Test} />
            <Route exact path="/register" component={Signup} />
            <Route exact path="/login" component={Login} />
          </Switch>
        </BrowserRouter>
      </div>
      <AuthVerify logOut={logOut} />
    </Fragment>
  );
}

export default App;

【问题讨论】:

    标签: reactjs react-router react-router-dom


    【解决方案1】:

    我认为您的AuthVerify 没有问题,应该在位置更改时调用它。据我所知,您正在渲染AuthVerify 组件路由器渲染正在更改的路由。 AuthVerify 组件需要在路由器中呈现,以便它使用相同的路由上下文来处理不断变化的路由。

    function App() {
      return (
        <Fragment>
          <div className="App">
            <BrowserRouter>
              <Switch>
                <Route exact path="/" component={Home} />
                <PrivateRoute exact path="/test" component={Test} />
                <Route exact path="/register" component={Signup} />
                <Route exact path="/login" component={Login} />
              </Switch>
              <AuthVerify logOut={logOut} />
            </BrowserRouter>
          </div>
        </Fragment>
      );
    }
    

    我建议将AuthVerify 转换为自定义钩子,因为它不会呈现内容。

    const useRouteListener = (cb) => {
      const history = useHistory();
    
      useEffect(() => {
        return history.listen(cb);
      }, [cb, history]);
    }
    

    移动 Router 以包装 App 组件并调用 useRouteListener 挂钩并传递您的注销令牌处理程序。 checkToken 这是一个回调,它会检查 JWT 是否过期并有条件地调用您的注销过程。

    function App() {
      useRouteListener(checkToken);
    
      return (
        <Fragment>
          <div className="App">
            <Switch>
              <Route exact path="/" component={Home} />
              <PrivateRoute exact path="/test" component={Test} />
              <Route exact path="/register" component={Signup} />
              <Route exact path="/login" component={Login} />
            </Switch>
          </div>
        </Fragment>
      );
    }
    

    【讨论】:

    • 感谢它的工作!您能否详细说明将其转换为自定义钩子?特别是在“移动路由器以包装 App 组件并调用 useRouteListener 挂钩并传递您的注销令牌处理程序”部分。
    • @GouravThakur 当然...路由器只需要在 React 树中更高的位置,以便为所有 LinkRouteSwitch 和 RRD 钩子提供路由上下文.如果App 是渲染路由上下文的组件,那么它也不能订阅上下文。将其转换为钩子更多是为了简化代码。您可以将其保留为组件并渲染null,但您真正想要的只是让useEffect 挂钩运行一次并设置历史监听器。
    【解决方案2】:

    让我们使用 react-router-dom 的 useLocation 钩子

    //import the useLocation
    import { BrowserRouter, Switch, Route,useLocation } from "react-router-dom";
    
    let location = useLocation()
    
    useEffect(()=>{
    //do whatever want to perform, just make sure it is in parent component
    logOut()
    },[location])
    
    
    const logOut = () => {
      localStorage.removeItem("accessToken");
      localStorage.removeItem("refreshToken");
    };
    
    function App() {
      return (
        <Fragment>
          <div className="App">
            <BrowserRouter>
              <Switch>
                <Route exact path="/" component={Home} />
                <PrivateRoute exact path="/test" component={Test} />
                <Route exact path="/register" component={Signup} />
                <Route exact path="/login" component={Login} />
              </Switch>
            </BrowserRouter>
          </div>
          <AuthVerify logOut={logOut} />
        </Fragment>
      );
    }
    

    【讨论】:

    • 这将在每次路由更改时注销用户。
    • 如果你看到我提到的我的评论,你可以做任何你想做的事。如果您想在注销之前进行身份验证,只需在 useEffect 中添加逻辑
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-10
    • 2021-03-21
    • 2019-12-07
    • 1970-01-01
    • 2013-05-10
    • 2022-01-25
    • 1970-01-01
    相关资源
    最近更新 更多