文章目录
- 🟢双token无感刷新
- 1、token过期续期的五种方案对比
- 2、双token的基本概念
- 3、双token无感刷新的原理
- 4、双token无感刷新的实现方式
- 5.前端实现
- ✒️总结
🟢双token无感刷新
对于token无感刷新这个东西有复杂度的话,它主要在后端,它前端有啥复杂度,我估计吧,可能大多数对这个无感token刷新的概念不清除。所以本篇文章主要针对这块梳理一下。
双token无感刷新是一种在Web开发中常用的安全及用户体验优化技术,主要涉及到两种类型的token:Access Token(访问令牌)和Refresh Token(刷新令牌)。以下是对双token无感刷新的详细解释
1、token过期续期的五种方案对比
- token过期后
- 方案一:跳登录页=>突然需要登录体验不好
- 方案二:刷新token重新发=>一直不用登录(但也可以设置过期时间)
- 方案三:每次请求都刷新token=>服务器计算压力大
- 方案四:token不过期、redis记录过期=>服务端维护用户身份
- 方案五:双token(token1正常使用、token2用来刷新token)
2、双token的基本概念
- Access Token(访问令牌):
- 用户直接用于访问受保护资源的凭证。
- 有效期较短,通常几分钟到几小时,一旦过期,用户需要重新认证以获取新的Access Token。
- 即使Access Token被泄露,由于其有效期短,攻击者利用它进行不当操作的时间窗口有限。
- Refresh Token(刷新令牌):
- 用于在Access Token过期后或过期前的一个定时间内重新获取新的Access Token。
- 有效期通常较长,甚至可以说是永久的,但出于安全考虑,一般会设置过期时间或使用次数限制。
- Refresh Token通常不会直接发送给客户端,而是保存在服务器端或经过加密后存储在客户端本地(如localStorage或sessionStorage)。
3、双token无感刷新的原理
双token无感刷新的核心在于自动在后台处理Access Token的过期和刷新过程,而无需用户重新登录或感知到这一过程。具体步骤如下:
1.用户登录
- 用户通过用户名(账号)、密码或其他认证方式向认证服务器请求授权。
- 认证成功后,服务器返回Access Token和Refresh Token给前端。
2.请求受保护资源
- 前端在访问受保护资源时,将Access Token放入请求头中发送给后端。
- 如果Access Token有效,后端正常处理请求并返回结果。
3.请求受保护资源
- 如果Access Token过期,后端会返回一个错误响应(如HTTP 401 Unauthorized)。
- 前端在接收到错误响应后,自动在后台使用Refresh Token向认证服务器请求新的Access Token。
- 刷新Access Token
- 认证服务器验证Refresh Token的有效性后,返回一个新的Access Token和(可选的)新的Refresh Token。
- 前端更新本地存储的Access Token和Refresh Token,并重新发起之前的请求。
4、双token无感刷新的实现方式
双token无感刷新的实现通常依赖于前端和后端的配合。以下是一个简化的实现流程:
- 前端:
- 在请求拦截器中拦截请求,检查Access Token是否即将过期或已过期。
- 如果Access Token过期,则自动使用Refresh Token请求新的Access Token,并更新本地存储。
- 将之前因Access Token过期而失败的请求重新发起。
- 将之前因Access Token过期而失败的请求重新发起。
- 验证Access Token的有效性。。
- 如果Access Token过期,返回错误响应,并允许使用Refresh Token来刷新Access Token。
- 验证Refresh Token的有效性,并返回新的Access Token和(可选的)新的Refresh Token。
5.前端实现
- 设置全局Axios拦截器
import axios from 'axios';
import store from './store'; // 假设你有一个Vuex或Redux等状态管理库 // 创建axios实例
const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, // api的base_url timeout: 5000 // 请求超时时间
}); // 请求拦截器
service.interceptors.request.use( config => { // 从状态管理库或其他地方获取token const accessToken = store.getters.accessToken; if (accessToken) { config.headers['Authorization'] = `Bearer ${accessToken}`; } return config; }, error => { // 处理请求错误 console.error('请求错误:', error); // for debug Promise.reject(error); }
); // 响应拦截器
service.interceptors.response.use( response => { // 响应正常则返回 return response; }, error => { // 响应错误处理 const { config, response, code } = error; // 检查是否是401错误(未授权),且是由于token过期导致 if (response && response.status === 401 && response.data.code === 'TOKEN_EXPIRED') { // 调用刷新token的函数 return refreshToken(config).then(accessToken => { // token刷新成功,重新请求 config.headers['Authorization'] = `Bearer ${accessToken}`; return service(config); }).catch(err => { // token刷新失败,清除tokens并跳转到登录页面 store.commit('clearTokens'); // 你可以在这里进行页面跳转等操作 window.location.href = '/login'; return Promise.reject(err); }); } // 其他错误直接返回 return Promise.reject(error); }
); // 刷新token的函数
function refreshToken(config) { return new Promise((resolve, reject) => { const refreshToken = store.getters.refreshToken; if (!refreshToken) { reject('No refresh token'); } // 发送请求以刷新token axios.post('/api/auth/refresh-token', { refreshToken }) .then(response => { // 更新state中的token store.commit('updateAccessToken', response.data.accessToken); resolve(response.data.accessToken); }) .catch(err => { reject(err); }); });
} export default service;
- 状态管理(Vuex示例)
// store.js
const store = new Vuex.Store({ state: { accessToken: localStorage.getItem('accessToken') || '', refreshToken: localStorage.getItem('refreshToken') || '' }, getters: { accessToken: state => state.accessToken, refreshToken: state => state.refreshToken }, mutations: { updateAccessToken(state, accessToken) { state.accessToken = accessToken; localStorage.setItem('accessToken', accessToken); }, clearTokens(state) { state.accessToken = ''; state.refreshToken = ''; localStorage.removeItem('accessToken'); localStorage.removeItem('refreshToken'); } }
}); export default store;
✒️总结
如果这篇【文章】有帮助到你💖,希望可以给我点个赞👍,创作不易,如果有对前端端或者对python感兴趣的朋友,请多多关注💖💖💖,咱们一起探讨和努力!!!
👨🔧 个人主页 : 前端初见