JWT 令牌过期后如何在路由更改时注销用户?

How can I logout user on route change once JWT token is expired?

我正在使用 Passport JWT,我想检查 JWT 令牌的有效性以在其已过期时执行注销。我已经让它在页面刷新时起作用,但在路由更改时不起作用(例如,从导航栏)。每次重新渲染 any 路由组件时,我都需要找到一种方法来检查它,而且我知道我很可能不需要在每个组件上都这样做。我只是不知道如何

这是用于页面刷新的代码:

快递

authenticated.js

router.route("/").get((req, res) => {
  passport.authenticate("jwt", { session: false }, (err, user, info) => {
    if (!user) {
      res.status(401);
      res.send("Unauthorized")
    }
  })(req, res);
});

module.exports = router;

反应

AuthContext.js

export const AuthContext = createContext();

function AuthProvider({ children }) {
  const [isLoaded, setIsLoaded] = usePersistedState(false, "loaded");
  const [user, setUser] = usePersistedState(null, "username");
  const [isAuthenticated, setIsAuthenticated] = usePersistedState(
    false,
    "auth"
  );

  useEffect(() => {
    axios
      .get("/authenticated")
      .then((response) => {
        return;
      })
      .catch((error) => {
        setUser("");
        setIsAuthenticated(false);
        setIsLoaded(true);
      });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  return (
    <div>
      {!isLoaded ? (
        <h3>Loading...</h3>
      ) : (
        <AuthContext.Provider
          value={{ user, setUser, isAuthenticated, setIsAuthenticated }}
        >
          {children}
        </AuthContext.Provider>
      )}
    </div>
  );
}

export default AuthProvider;

index.js

ReactDOM.render(
  <AuthProvider>
    <App />
  </AuthProvider>,
  document.getElementById("root")
);

更新

我试图通过在我的 PrivateOutlet.js 上添加这个 useEffect 函数来完成它,它处理私有路由,但没有成功:

function PrivateOutlet() {
  const authContext = useContext(AuthContext);

  const location = useLocation();

  useEffect(() => {
    axios
      .get("/authenticated")
      .then((response) => {
        return;
      })
      .catch((err) => {
        authContext.setIsAuthenticated(false);
        authContext.setUser("");
      });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [location]);

  return authContext.isAuthenticated ? (
    <Outlet />
  ) : (
    <Navigate to="/login" replace state={{ path: location.pathname }} />
  );
}

export default PrivateOutlet;

响应不特定于任何 platform/language。一般来说,认证provider/service就是给客户端颁发token。该令牌用于在资源服务器验证后访问私有资源。当您使用 JWT token 时,资源 server/service 可以在不与身份验证服务对话或不执行数据库查找的情况下验证令牌。您的服务器端代码始终需要使用传入请求验证令牌,您可以通过为受保护的请求创建拦截器来实现。简而言之,您可以在需要时调用来自客户端的调用来验证令牌。

它可能是通过包装器组件进行检查的套接字调用。如果socketreturnsfalse,那么history.push他进入一个不需要登录的页面

原始问题的“更新”部分中列出的方法是正确的,但是我的代码中有一些警告阻止它正常工作。

我忘记将 useEffect()AuthContext.js 移至 PrivateOutlet.js 后删除,并且我还修改了依赖项数组以包含 location.pathname 而不是仅包含 location:

PrivateOutlet.js

function PrivateOutlet() {
  const authContext = useContext(AuthContext);

  const location = useLocation();

  useEffect(() => {
    axios
      .get("/authenticated")
      .then((response) => {
        return;
      })
      .catch((err) => {
        authContext.setIsAuthenticated(false);
        authContext.setUser("");
      });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [location.pathname]);

  return authContext.isAuthenticated ? (
    <Outlet />
  ) : (
    <Navigate to="/login" replace state={{ path: location.pathname }} />
  );
}

export default PrivateOutlet;

这是一个小改动,可能根本不会影响任何事情,但是在 authenticated.js 我的 Express 服务器上,我刚刚从使用自定义回调回到标准 Passport 回调,允许它自行处理未经授权的调用:

authenticated.js

router
  .route("/")
  .get(passport.authenticate("jwt", { session: false }), (req, res) => {
    //do some stuff
    res.json();
  });

module.exports = router;