在前端实现双令牌(又称刷新令牌和访问令牌)的无感刷新可以通过以下步骤实现:

  1. 保存令牌:在用户登录成功后,将访问令牌(access token)和刷新令牌(refresh token)保存在客户端的本地存储中,如 sessionStorage 或 localStorage。
  2. 访问令牌的过期时间:在保存访问令牌时,同时保存访问令牌的过期时间。
  3. 定时刷新:在每次发送请求前,检查访问令牌是否过期。如果过期,则使用刷新令牌去获取新的访问令牌。为了避免同时发送多个刷新令牌请求,可以使用互斥锁或者请求队列来保证只有一个刷新令牌请求在进行中。
  4. 处理刷新令牌响应:获取到新的访问令牌后,更新本地存储中的访问令牌和过期时间,并继续原来的请求。
  5. 处理刷新令牌失败:如果刷新令牌失败(如刷新令牌过期或者无效),则需要引导用户重新登录或者执行其他的错误处理逻辑。

下面是一个简单的示例代码:

let isRefreshing = false; // 是否正在刷新令牌
const refreshTokenQueue = []; // 刷新令牌队列

// 发送请求之前的拦截器,检查访问令牌是否过期
axios.interceptors.request.use(config => {
    const accessToken = localStorage.getItem('accessToken');
    const accessTokenExpireTime = localStorage.getItem('accessTokenExpireTime');
    if (accessToken && accessTokenExpireTime && Date.now() > parseInt(accessTokenExpireTime)) {
        // 访问令牌过期,进行刷新操作
        return refreshToken(config);
    }
    return config;
});

// 刷新令牌的函数
function refreshToken(config) {
    if (!isRefreshing) {
        isRefreshing = true;
        const refreshToken = localStorage.getItem('refreshToken');
        return axios.post('/refresh_token', { refreshToken })
            .then(response => {
                const { accessToken, refreshToken } = response.data;
                localStorage.setItem('accessToken', accessToken);
                localStorage.setItem('refreshToken', refreshToken);
                const newAccessTokenExpireTime = Date.now() + 3600 * 1000; // 假设访问令牌有效期为1小时
                localStorage.setItem('accessTokenExpireTime', newAccessTokenExpireTime);
                // 重新发送原来的请求
                config.headers.Authorization = `Bearer ${accessToken}`;
                refreshTokenQueue.forEach(cb => cb(accessToken));
                refreshTokenQueue.length = 0;
                return axios(config);
            })
            .catch(error => {
                // 处理刷新令牌失败的情况
                return Promise.reject(error);
            })
            .finally(() => {
                isRefreshing = false;
            });
    } else {
        // 正在刷新令牌,将请求添加到刷新令牌队列中
        return new Promise(resolve => {
            refreshTokenQueue.push(newAccessToken => {
                config.headers.Authorization = `Bearer ${newAccessToken}`;
                resolve(axios(config));
            });
        });
    }
}

// 发送请求
axios.get('/api/data')
    .then(response => {
        // 处理响应
    })
    .catch(error => {
        // 处理错误
    });

在上面的示例代码中,我们使用 Axios 库来发送请求,并通过拦截器实现了访问令牌的自动刷新。当发送请求时,会先检查访问令牌是否过期,如果过期则调用刷新令牌函数去获取新的访问令牌。如果同时有多个请求在进行中并且访问令牌过期,会将这些请求添加到刷新令牌队列中,并且只发送一个刷新令牌请求。

分类: JavaScript 标签: 暂无标签

评论

暂无评论数据

暂无评论数据

目录