以下是对前端双token无感刷新的图文详解:
一、概念介绍
- Token:
- Token是一种用户标识,表示用户身份,类似于身份证件。它是在服务端产生的。如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么服务端会返回Token给前端。前端可以在每次请求时带上Token,以证明自己的合法地位。
- 双Token:
- 双Token机制涉及两种类型的Token:Access Token(访问令牌)和Refresh Token(刷新令牌)。
- Access Token:用户直接用于访问受保护资源的凭证,有效期较短,通常几分钟到几小时。一旦过期,用户需要重新认证以获取新的Access Token。即使Access Token被泄露,由于其有效期短,攻击者利用它进行不当操作的时间窗口有限。
- Refresh Token:用于在Access Token过期后或过期前的一个定时间内重新获取新的Access Token。有效期通常较长,甚至可以说是永久的,但出于安全考虑,一般会设置过期时间或使用次数限制。Refresh Token通常不会直接发送给客户端,而是保存在服务器端或经过加密后存储在客户端本地(如localStorage或sessionStorage)。
二、双Token无感刷新详解
实现原理:
- 双Token无感刷新的核心在于自动在后台处理Access Token的过期和刷新过程,而无需用户重新登录或感知到这一过程。
- 用户通过用户名(账号)、密码或其他认证方式向认证服务器请求授权。
- 认证成功后,服务器返回Access Token和Refresh Token给前端。
- 前端在访问受保护资源时,将Access Token放入请求头中发送给后端。
- 如果Access Token有效,后端正常处理请求并返回结果。
- 如果Access Token过期,后端会返回一个错误响应(如HTTP 401 Unauthorized)。
- 前端在接收到错误响应后,自动在后台使用Refresh Token向认证服务器请求新的Access Token。
- 认证服务器验证Refresh Token的有效性后,返回一个新的Access Token和(可选的)新的Refresh Token。
- 前端更新本地存储的Access Token和Refresh Token,并重新发起之前的请求。
实现步骤:
- 前端实现:
- 设置全局Axios拦截器,用于在请求和响应阶段拦截和处理Token。
- 在请求拦截器中,从本地存储中获取Access Token,并将其添加到请求头中。
- 在响应拦截器中,检查后端返回的响应码。如果响应码表示Access Token过期,则自动使用Refresh Token请求新的Access Token。
- 更新本地存储中的Access Token和Refresh Token,并重新发起因Access Token过期而失败的请求。
- 后端实现:
- 在认证成功后,生成并返回Access Token和Refresh Token给前端。
- 在验证Access Token时,如果检测到其已过期,则返回错误响应,并提示前端使用Refresh Token进行刷新。
- 在验证Refresh Token时,如果其有效,则返回新的Access Token和(可选的)新的Refresh Token给前端。
示例代码:
- 前端Axios拦截器设置示例(伪代码):
import axios from 'axios';
import { getToken, setToken, getRefreshToken, setRefreshToken } from './tokenUtils';
import router from '@/router';
const service = axios.create({
baseURL: 'http://your-api-base-url',
timeout: 5000,
});
service.interceptors.request.use(
config => {
const accessToken = getToken();
if (accessToken) {
config.headers['Authorization'] = `Bearer ${accessToken}`;
}
return config;
},
error => {
// 处理请求错误
return Promise.reject(error);
}
);
service.interceptors.response.use(
response => {
return response;
},
error => {
const { response, config } = error;
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并跳转到登录页面
// 你可以在这里进行页面跳转等操作
router.push('/login');
return Promise.reject(err);
});
}
return Promise.reject(error);
}
);
function refreshToken(config) {
const refreshToken = getRefreshToken();
if (!refreshToken) {
return Promise.reject('No refresh token');
}
return axios.post('/api/auth/refresh-token', { refreshToken }).then(response => {
setToken(response.data.accessToken);
setRefreshToken(response.data.refreshToken);
return response.data.accessToken;
}).catch(err => {
return Promise.reject(err);
});
}
export default service;
- 后端Token生成与验证逻辑示例(伪代码,以Java为例):
// 生成Token的工具类
public class TokenUtils {
// 使用JWT或其他方式生成Token
public static String generateAccessToken(String userId) {
// 生成Access Token的逻辑
}
public static String generateRefreshToken(String userId) {
// 生成Refresh Token的逻辑
}
}
// 认证服务器接口
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest loginRequest) {
// 验证用户名和密码
// ...
String userId = // 获取用户ID的逻辑
String accessToken = TokenUtils.generateAccessToken(userId);
String refreshToken = TokenUtils.generateRefreshToken(userId);
// 返回Access Token和Refresh Token给前端
return ResponseEntity.ok(new LoginResponse(accessToken, refreshToken));
}
@PostMapping("/refresh-token")
public ResponseEntity<?> refreshToken(@RequestBody RefreshTokenRequest refreshTokenRequest) {
String refreshToken = refreshTokenRequest.getRefreshToken();
// 验证Refresh Token的有效性
// ...
String newAccessToken = TokenUtils.generateAccessToken(userId); // 重新生成新的Access Token
// 可选:生成新的Refresh Token
// String newRefreshToken = TokenUtils.generateRefreshToken(userId);
// 返回新的Access Token(和可选的新的Refresh Token)给前端
return ResponseEntity.ok(new RefreshTokenResponse(newAccessToken /*, newRefreshToken*/));
}
}
三、注意事项
- 安全性:
- 确保Refresh Token的安全存储和传输,避免其被泄露。
- 设置合理的Token过期时间,以平衡安全性和用户体验。
- 性能:
- 在使用双Token机制时,需要注意对后端接口的调用频率,避免对服务器造成过大的压力。
- 可以通过缓存等技术手段来优化性能。
- 用户体验:
- 在实现双Token无感刷新时,要确保用户在使用过程中不会感知到Token的刷新过程,以提高用户体验。
- 在Token刷新失败时,要提供友好的错误提示和引导用户重新登录。
通过以上介绍和示例代码,相信读者已经对前端双Token无感刷新有了深入的了解。在实际项目中,可以根据具体需求进行灵活的应用和调整。
© 版权声明
文中内容均来源于公开资料,受限于信息的时效性和复杂性,可能存在误差或遗漏。我们已尽力确保内容的准确性,但对于因信息变更或错误导致的任何后果,本站不承担任何责任。如需引用本文内容,请注明出处并尊重原作者的版权。
THE END
暂无评论内容