无感刷新机制:智能系统的新宠儿?
创作时间:
作者:
@小白创作中心
无感刷新机制:智能系统的新宠儿?
引用
CSDN
等
9
来源
1.
https://blog.csdn.net/qq_36208612/article/details/139545599
2.
https://blog.csdn.net/m0_58600248/article/details/138916457
3.
https://m.blog.csdn.net/2401_89323925/article/details/145165700
4.
https://cloud.baidu.com/article/3211839
5.
https://blog.csdn.net/u012723183/article/details/136700195
6.
https://zhidao.baidu.com/question/1958727165501063588.html
7.
https://zhidao.baidu.com/question/2000771775062192627.html
8.
https://juejin.cn/post/7356240651040489487
9.
https://www.showapi.com/news/article/677dea394ddd79f11a1bcef4
在现代Web应用中,使用Token进行身份验证是一种常见方法。然而,当Token过期时,用户需要重新登录才能继续访问受保护资源,这会打断用户体验。引入了无感刷新机制后,即使Token即将过期,也能自动刷新,使用户在无感知的情况下继续操作。这种机制不仅提升了用户体验,还保证了系统的安全性。具体实现需根据项目需求和技术栈进行调整。
01
无感刷新机制的技术原理
无感刷新机制的核心是在Token过期前自动获取新的Token,确保用户会话的连续性。其基本流程如下:
- 检测过期:在请求发送前或响应返回时检查Token的有效期。
- 刷新逻辑:
- 使用Refresh Token获取新的Access Token(前端场景)。
- 通过过滤器自动刷新JWT Token(后端场景,如Spring Boot)。
这种机制的关键在于:
- 双Token机制:使用短有效期的Access Token和长有效期的Refresh Token。
- 自动刷新:在Token过期前自动发起刷新请求。
- 透明处理:刷新过程对用户完全透明,不影响正常使用。
02
前端实现示例
在前端应用中,通常使用Axios拦截器来实现无感刷新。以下是一个基于Vue.js的示例:
import axios from 'axios';
import store from './store';
axios.interceptors.request.use(config => {
const token = store.state.token;
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
}, error => {
return Promise.reject(error);
});
axios.interceptors.response.use(response => {
return response;
}, async function (error) {
if (error.response.status === 401) {
try {
const refreshToken = store.state.refreshToken;
const res = await axios.post('/refresh_token', { refreshToken });
store.commit('setToken', res.data.accessToken);
store.commit('setRefreshToken', res.data.refreshToken);
return axios(error.config);
} catch (refreshError) {
store.commit('logout');
router.push('/login');
}
}
return Promise.reject(error);
});
在这个示例中:
- 请求拦截器负责在请求头中添加Token。
- 响应拦截器捕获401错误(Token过期),触发刷新逻辑。
- 使用Refresh Token获取新Token,并更新存储中的Token。
- 刷新成功后重新发送原始请求。
03
后端实现示例
在后端,以Spring Boot为例,可以通过JWT工具类和过滤器实现无感刷新:
public class JwtTokenUtil {
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public boolean validateToken(String token, UserDetails userDetails) {
final String username = getUsernameFromToken(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
private boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
}
public class JwtRequestFilter extends OncePerRequestFilter {
@Autowired
private JwtUserDetailsService userDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String requestTokenHeader = request.getHeader("Authorization");
String username = null;
String jwtToken = null;
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
jwtToken = requestTokenHeader.substring(7);
try {
username = jwtTokenUtil.getUsernameFromToken(jwtToken);
} catch (IllegalArgumentException e) {
logger.warn("Unable to get JWT Token");
} catch (ExpiredJwtException e) {
logger.warn("JWT Token has expired");
}
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
chain.doFilter(request, response);
}
}
在这个示例中:
JwtTokenUtil
负责生成和验证JWT Token。JwtRequestFilter
在请求到达控制器前检查Token,必要时自动刷新并放行。
04
微信小程序实现
在微信小程序中,无感刷新机制的实现与前端Web应用类似,但需要特别注意本地存储的安全性:
- 本地存储:保存Token和过期时间。
- 启动时验证:在
onLaunch
或onShow
中检查Token有效性,提前刷新即将过期的Token。 - 登录与刷新:提供刷新Token接口,失败时重新登录。
// app.js
App({
onLaunch: function () {
const token = wx.getStorageSync('token');
const refreshToken = wx.getStorageSync('refreshToken');
const tokenExpireTime = wx.getStorageSync('tokenExpireTime');
if (token && refreshToken && tokenExpireTime > Date.now()) {
this.checkTokenValidity();
}
},
checkTokenValidity: function () {
wx.request({
url: 'https://your-api.com/check_token',
method: 'GET',
header: {
'Authorization': 'Bearer ' + wx.getStorageSync('token')
},
success: (res) => {
if (res.data.code === 401) {
this.refreshToken();
}
}
});
},
refreshToken: function () {
wx.request({
url: 'https://your-api.com/refresh_token',
method: 'POST',
data: {
refreshToken: wx.getStorageSync('refreshToken')
},
success: (res) => {
if (res.data.code === 200) {
wx.setStorageSync('token', res.data.token);
wx.setStorageSync('tokenExpireTime', Date.now() + res.data.expiresIn * 1000);
} else {
wx.removeStorageSync('token');
wx.removeStorageSync('refreshToken');
wx.navigateTo({
url: '/pages/login/login'
});
}
}
});
}
});
05
最佳实践
- 双Token机制:Access Token设置较短有效期(如15分钟),Refresh Token设置较长有效期(如1小时)。
- 前端实现要点:
- 使用拦截器处理Token刷新逻辑。
- 设置标志位防止重复刷新。
- 缓存待执行的请求,在Token刷新成功后重新发送。
- 后端实现要点:
- 提供安全的Token刷新接口。
- 使用过滤器检查Token有效性。
- 确保Refresh Token的安全存储和传输。
- 错误处理:如果Token刷新失败,应引导用户重新登录,并提供友好的提示信息。
- 安全性考虑:
- Refresh Token也需要定期更新,避免长期暴露。
- 注意防止XSS和CSRF攻击。
- 使用HTTPS确保数据传输安全。
06
未来趋势
随着技术的发展,无感刷新机制可能会有以下改进方向:
- 智能刷新策略:根据用户行为和网络状况动态调整刷新时机。
- 多因素认证集成:结合生物识别等技术,提供更安全的无感认证体验。
- 统一身份管理:在跨平台和跨设备场景下实现无缝的无感刷新。
- 隐私保护增强:在保证用户体验的同时,进一步加强用户隐私保护。
无感刷新机制通过智能的技术手段,解决了传统Token认证方式中用户需要频繁登录的问题,既提升了用户体验,又保证了系统的安全性。随着技术的不断进步,这种机制将在更多场景中得到应用,为用户带来更加便捷和安全的使用体验。
热门推荐
防治鱼病少不了用大蒜
渴望得到别人认可的心理
办公软件怎么学打字快
4S店 vs 修理厂:一位十年售后专家的专业解析
关系数据库模型与形式化查询语言详解
Windows 10摄像头故障排查指南:8个实用解决方案
安静,是种智慧
干燥、感冒来袭,别慌,这里有超强应对攻略!
物联卡流量池:全新视角看流量分配
腰椎间盘突出别担心,调整心态是关键!
表现主义:12幅经典画作及其作者
猫咪喜欢玩水却讨厌洗澡的两个原因,其中与它们“爱理毛”有关!
打印机打印不了word怎么回事 5个原因分析及解决方法
黄冈文旅发展经验:用好东坡超级IP,打造"苏迷"向往之城
从东方甄选的道歉潮看:危机公关中的品牌自救
崩牙驹风光不再,澳门为母亲办90岁寿宴来了好多网红,酒席亦普通
月收入3000元需要缴纳多少社保?
自配猪饲料指南:不同阶段猪饲料配方大全
治水攻坚三周年:中山岐江河畔夜生活焕发新活力
十类常见的浴室柜材质推荐 浴室柜材质哪种好
什么是BPO项目管理
肉瘤怎么消除掉
英雄联盟制作人深度解析 游戏平衡的艺术
瑞安市空间中心平台启航:智慧赋能,构筑城市未来新蓝图
干牛筋怎么泡发最好?牛筋怎么煮容易烂?
新手第一台胶卷相机买什么好
四川阿坝州精选旅游攻略:热门景点、线路规划与文化体验指南
高三数学提高复习效率的方法
资产负债率多少算正常范围?不同行业和发展阶段的差异
透视蛇年春节档:《战火西岐》票房难及《朝歌风云》,北京文化收获多少?