世界上最伟大的投资就是投资自己的教育

首页Ant Design Pro
随风 · 练气

【图文并茂】ant design pro 如何使用 refresh token 可续期 token 来提高用户体验

随风发布于103 次阅读


上一节 * 【图文并茂】ant design pro 如何对接后端个人信息接口

json web token


我们知道 token 就像身份证一样,但是它是有个过期时间的

比如说设为一个小时,

就像我们去访问微信支付那样,它们的 token 就是一个小时。

那我们的系统,你现在登录之后,你设了一个小时,过期时间,那它就在你登录之后的一个小时内一定会过期

无论你在中间有没有做访问

refresh token

问题出在这里,你中间一小时内,一直在操作,该过期还得过期,过期了,就要重新登录,未免体验太差了

我要的是,比如在一个如果中间有操作,你就帮我续下期。

比如说的这个中间,是七天内,只要七天内,当然你自己定,一天内也行,一天内只要有操作,你就一直帮我续一个小时。

这个时间是自己定的。

这里就涉及到两个时间。

JWT_EXPIRE=1d
REFRESH_JWT_EXPIRE=7d

比如这里有两个过期时间。

先看最后一个。

比如我现在登录了,那七天后会过期,我明天还有在操作,那就是七天后之后的过一天会过期

意思是,你只要在 REFRESH_JWT_EXPIRE 有效期内,有操作,那就一直延后七天,一直续。

也就是说这个时候会生成新的

REFRESH_JWT_SECRET

两个时间对应两个 token 的

JWT_SECRET


REFRESH_JWT_SECRET 这个是来续期用的

JWT_SECRET 这个应该叫 access_token ,来访问 api 用的,来验证的

所以 JWT_SECRET 这个可以设短一些,比如 一个小时。

一个小时后就过期了,别人拿到旧的也没用。

后端实现

先要实现 refresh Token 的 api

const refreshToken = handleAsync(async (req: Request, res: Response) => {
  try {
    const { refreshToken } = req.body;

    if (!refreshToken) {
      res.status(401);
      throw new Error('You are not authenticated!');
    }

    const decoded = jwt.verify(refreshToken, process.env.REFRESH_JWT_SECRET as string) as DecodedToken;
    const newRefreshToken = generateRefreshToken(decoded.id);

    res.json({
      success: true,
      token: generateToken(decoded.id),
      refreshToken: newRefreshToken,
    });
  } catch (err) {
    console.error(err);
    res.status(401);
    throw new Error(err.message || 'Not authorized, token failed');
  }
});

这里很简单,用旧的 refresh token 换新的,时间重新计算,继续延后七天,生成新的 access token 和 refresh token

新的 access token 可以让应用继续访问,

新的 refresh token 可以让租期延后。

所以 refresh token 从来不是解决安全问题的,只是解决体验问题。

const decoded = jwt.verify(refreshToken, process.env.REFRESH_JWT_SECRET as string) as DecodedToken;

这里总会验证老的 refresh. token 是否有效的。

如果无效,也就没后面啥事了。

前端实现

之前这里 【图文并茂】ant design pro 如何给后端发送 json web token - 请求拦截器的使用

要继续改一下。

  requestInterceptors: [
    async (config: RequestOptions) => {
      // 拦截请求配置,进行个性化处理。
      const url = config?.url;
      const accessToken = localStorage.getItem('token');

      if (url?.includes('/auth/refresh') || url?.includes('/auth/login')) {
        return {
          ...config,
          headers: { Authorization: `Bearer ${accessToken}` },
          url,
        };
      }

      let newToken;

      // refresh token
      if (accessToken) {
        const currentDate = new Date();
        const decodedToken: DecodedToken = jwtDecode<DecodedToken>(accessToken);

        // expired
        if (decodedToken.exp * 1000 < currentDate.getTime()) {
          // send refresh token
          const response = await refreshToken({
            refreshToken: localStorage.getItem('refreshToken')!,
          });
          if (response.success) {
            localStorage.setItem('token', response.token);
            localStorage.setItem('refreshToken', response.refreshToken);

            newToken = response.token;
          }
        }
      }

      return {
        ...config,
        headers: { Authorization: `Bearer ${newToken ?? accessToken}` },
        url,
      };
    },
  ],

那个请求请求拦截器部分要这样做

  if (url?.includes('/auth/refresh') || url?.includes('/auth/login')) {
    return {
      ...config,
      headers: { Authorization: `Bearer ${accessToken}` },
      url,
    };
  }

这里只是过滤掉不必要的 api

接下来

if (decodedToken.exp * 1000 < currentDate.getTime()) {

就去判断 access token 是否过期,过期才要续

只要 refresh token 不过期,总能续上新的

headers: { Authorization: Bearer ${newToken ?? accessToken} },

后面这里只是用续上的来代替旧的。

到此完成。

本站文章均为原创内容,如需转载请注明出处,谢谢。

0 条回复
暂无回复~~
喜欢
统计信息
    学员: 29811
    视频数量: 1987
    文章数量: 526

© 汕尾市求知科技有限公司 | Rails365 Gitlab | 知乎 | b 站 | csdn

粤公网安备 44152102000088号粤公网安备 44152102000088号 | 粤ICP备19038915号

Top