如何在ReactJS中使用刷新令牌

10

我正在使用ReactJS开发一个管理应用程序,其中使用Redux进行状态管理。当用户登录时,我的应用程序会获取access_tokenrefresh_tokenaccess_token在5分钟后会过期,此时token将变得无效,无法进行任何API端点请求。

我想知道如何使用refresh_token来更新存储在浏览器的localStorage中的access_token。在此之前,我对refresh_token一无所知。以下是我的登录请求和保存access_tokenrefresh_token的方式。

认证:

export  const Authentication = async(payload) =>{
    try{
    const response = await fetch(`${generalConfig.baseURL}/oauth/token`, {
        method: 'POST',
        cache: 'no-cache',
        headers: {
            'Authorization': `Basic ${btoa("topseller:topseller")}`,
            'Accept': '*/*',
            // 'Content-Type': 'multipart/form-data',
            'accept-encoding': 'gzip, deflate',
            
        },
        body: payload
    })
    .then((response)=>{
        console.log(response)
        return response.json()
    },err=>{
       console.log(err,'############')
    })
    console.log(response,'@@@@@@@@@')
    return response;
}catch(err){
    console.log(err,'############')
}
}

authentication.action:

export const getAccessToken = (dataToSend) => async (dispatch) => {
  try {
    var formData = ConvertToFormData(dataToSend);
    const authResponse = await Authentication(formData);   
    <-- See above about this Authentication function

    const response = await fetch("http://api.smartocart.com/userType", {
      method: "GET",
      cache: "no-cache",
      headers: {
        Authorization: `Bearer ${authResponse.access_token}`,
      },
    });
    const payload = await response.json();

    if (payload.status === "admin") {
      SaveToLocalStorage("access_token", authResponse.access_token);
      SaveToLocalStorage("refresh_token", authResponse.refresh_token);
      dispatch({
        type: GET_ACCESS_TOKEN,
        payload: {
          access_token: authResponse.access_token,
          refresh_token: authResponse.refresh_token,
        },
      });
    } else {
      dispatch({
        type: ERROR_ACCESS_TOKEN,
        buttonPressed: true,
      });
    }
  } catch (exception) {
    console.log("Log In again");
  }
};

我在一些博客文章中读到了这个,但是我并没有理解。 https://nmajor.com/posts/access-and-refresh-token-handling-with-redux 非常感谢您的帮助。

2个回答

9

你可以在app.js上添加令牌到期时间验证,这样,如果您重新加载应用程序或转到下一页,或者如果您进行API调用,它将始终检查令牌到期时间验证,如果令牌过期,它将调用获取更新令牌的请求。

请参考下面的示例:我提供了使用React Axios的示例。

axios.interceptors.request.use(async (config) => {
  const expireAt = localStorage.getItem('expiresAt');
  let token = localStorage.getItem('authToken');
  if (dayjs(expireAt).diff(dayjs()) < 1) {
    const data = onGetForcedToken();
    token = typeof data === 'string' ? data : await data();
  }
  // setting updated token
  localStorage.setItem('authToken', token);
  return config;
}, (err) => {
   console.log("error in getting ",err)
});

1
这里的 dayjs 是什么?你能解释一下吗? - aditya kumar
1
这个例子是基于axios,如你所提到的,但问题的代码却是基于fetch。 - Diego Molina
1
如果令牌存储在cookie中,会怎样? - mirsahib
@mirsahib,在这种情况下,您需要在服务器端设置一个终端点来检查存储在cookie中的令牌。服务器会检查该令牌,如果过期或无效,则返回403。然后前端会看到刷新令牌终端点响应的状态码403,删除任何存储的数据(从localStorage中的access_token),并将用户重定向到登录页面。通过登录页面,用户应该登录并获取新的访问和刷新令牌。 - khashashin
您还应该将令牌设置为空字符串或删除cookies。这是由服务器完成的。 - khashashin
显示剩余3条评论

0
如果您正在使用Axios,可以通过拦截器拦截请求,并调用API获取新的令牌以防令牌过期。
另一种获取新令牌的方法是在令牌过期之前定期调用API。
例如,在App.js中。
// Get new Token
const getNewUserToken = async () => {
    const submitUrl = apiRoot + "/v1/user/refreshtoken";
    try {
        const res = await fetch(submitUrl, {
            method: "GET",
            headers: {
                token: localStorage.getItem("token"),
                "Content-Type": "application/json",
            },
        });

        if (res.status === 200) {
            const data = await res.json();
            localStorage.setItem("token", data.token);
        } else {
            // New token didnt received.Remove the previous token and user 
            localStorage.removeItem("token");
            localStorage.removeItem("user");
            setUser({});
            navigate("/");
        }
    } catch (err) {
        console.log(err);
    }
};
const intervalRef = useRef();
const getToken = useCallback(() => {
    // Get new token if and only if existing token is available
    if (localStorage.getItem("token") != null) {
        getNewUserToken();
    }
}, []);

// Trigger API to get a new token before token gets expired.
useEffect(() => {
    const interval = setInterval(() => getToken(), 1000 * 60 * 6); // 6 minutes interval as our token will expire after 7 minutes.
    intervalRef.current = interval;
    return () => clearInterval(interval);
}, [getToken]);

希望这对您自动刷新令牌并避免强制用户登录有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接