首页 > 解决方案 > 在反应应用程序中检查 JWT 过期

问题描述

所以我创建了这些上下文来处理登录用户并将登录用户检索到可能需要它的任何组件。

他们来了:

context.js

import React, { useReducer } from "react";
import { AuthReducer, initialState } from "./reducers";

const AuthStateContext = React.createContext();
const AuthDispatchContext = React.createContext();

export function useAuthState() {
  const context = React.useContext(AuthStateContext);
  if (context === undefined) {
    throw new Error("useAuthState must be used within a AuthProvider");
  }

  return context;
}

export function useAuthDispatch() {
  const context = React.useContext(AuthDispatchContext);
  if (context === undefined) {
    throw new Error("useAuthDispatch must be used within a AuthProvider");
  }

  return context;
}

export const AuthProvider = ({ children }) => {
  const [user, dispatch] = useReducer(AuthReducer, initialState);

  return (
    <AuthStateContext.Provider value={user}>
      <AuthDispatchContext.Provider value={dispatch}>
        {children}
      </AuthDispatchContext.Provider>
    </AuthStateContext.Provider>
  );
}

reducers.js

let user = localStorage.getItem("currentUser")
  ? JSON.parse(localStorage.getItem("currentUser")).user
  : "";
let token = localStorage.getItem("currentUser")
  ? JSON.parse(localStorage.getItem("currentUser")).token
  : "";

export const initialState = {
  userDetails: user || "",
  token: token || "",
  loading: false,
  errorMessage: null,
};

export const AuthReducer = (initialState, action) => {
  switch (action.type) {
    case "REQUEST_LOGIN":
      return {
        ...initialState,
        loading: true,
      };
    case "LOGIN_SUCCESS":
      return {
        ...initialState,
        userDetails: action.payload.user,
        token: action.payload.token,
        loading: false,
      };
    case "LOGOUT":
      return {
        ...initialState,
        userDetails: "",
        token: "",
      };

    case "LOGIN_ERROR":
      return {
        ...initialState,
        loading: false,
        errorMessage: action.error,
      };

    default:
      throw new Error(`Unhandled action type: ${action.type}`);
  }
};

actions.js

const ROOT_URL = process.env.REACT_APP_API_HOST_URL;

export async function loginUser(dispatch, loginPayload) {
  const requestOptions = {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(loginPayload),
  };

  try {
    dispatch({ type: "REQUEST_LOGIN" });
    let response = await fetch(`${ROOT_URL}/auth/login`, requestOptions);
    let data = await response.json();

    if (data.user) {
      dispatch({ type: "LOGIN_SUCCESS", payload: data });
      localStorage.setItem("currentUser", JSON.stringify(data));
      return data;
    }

    dispatch({ type: "LOGIN_ERROR", error: data.errors[0] });
    return;
  } catch (error) {
    dispatch({ type: "LOGIN_ERROR", error: error });
  }
}

export async function logout(dispatch) {
  dispatch({ type: "LOGOUT" });
  localStorage.removeItem("currentUser");
  localStorage.removeItem("token");
}

我的问题是如何扩展它以检查每次useAuthState()调用钩子时 JWT 是否已过期(如果这甚至是最好的处理方式)?然后将用户注销或从服务器刷新令牌,而无需尽可能将用户注销。

提前致谢。

标签: javascriptreactjs

解决方案


使用 JWT,您可以在没有密钥的情况下在浏览器中解密自己的令牌。通过这种方式,您可以检查 JWT 令牌是否即将过期或已经过期。密钥仅用于其签名位置的真实性。这在智威汤逊网站上得到了很好的证明。

如果您希望能够从过期的 JWT 重新生成密钥,您可以在服务器上的 jsonwebtoken 函数中设置为,但是ignoreExpiration为什么还要首先设置过期时间呢?最好只允许在 JWT 即将到期时重新生成它。trueverify()


推荐阅读