问题1:如何使jwt生成的 token在用户登出之后失效?
由于jwt生成的token是无状态的,这体现在我们在每一次请求时 request都会新建一个session对象:
举个例子:
@PostMapping(value = "/authentication/logout")
public ResponseEntity<BaseResult> logOut(HttpServeletRequest request ,@RequestHeader(name = "Authorization") String authHeader) throws AuthenticationException, IOException {
HttpSession session =request.getSession();
session.isNew();//true
return null;}
这就会导致我们在退出系统之后,使用原token依然有机会被系统检验通过,而有权限访问系统;
所以我们需要借助别的方式使得该token失效(并不是token真正失效而是将其加入黑名单或者使用别的什么方式标记它);
1,加入黑名单的方式需要额外的占用存储空间,本次暂未考虑该方式;
2,除了加,我们还可以使用减法的方式来实现:
首先我们在redis中将用户登陆的token存起来,
这里要考虑用户可以多端同时登陆(即每个设备都会产生一个token),如果一个设备登出而不想影响其他设备的登录,此时就要将登出的那个token单独处理;
这里做了一个设计是"将所有用户(同一用户)登录token已list的形式存在redis中",如果一个用户登出,则将该用户的token从list中删除,下次请求时会校验list中是否有该key,如果有放行,否则就要重新登录;
代码实现:
登陆时缓存token:
HttpStatus httpStatus;
BaseResult baseResult;
HttpHeaders httpHeaders = new HttpHeaders();
String password = RSAUtils.privateDecrypt(user.getPassword(), RSAUtils.getPrivateKey(Const.PRIVATE_KEY));
if (!HmrsUtils.isValidPassword(password)) {
log.error("密码不匹配:{}", user.getUsername());
throw new PasswordLengthException();
}
//登陆的时候考虑浏览器的因素,可以多个浏览器同时登录一个账号
String token = authService.login(user.getUsername(), password);
if (StrUtil.isEmpty(token)) {
httpHeaders.add("Authorization", null);
httpStatus = HttpStatus.BAD_REQUEST;
baseResult = HmrsUtils.setHttpBaseResult(httpStatus.value(), "登录失败", "用户名/密码错误");
} else {
httpHeaders.add("Authorization", token);
httpStatus = HttpStatus.OK;
baseResult = HmrsUt