登录接口
在上文中 我们已经设置了自定义登录接口自定义拦截器jwt登录校验接口模拟账号登录_jwt自定义拦截器-CSDN博客https://blog.csdn.net/2202_75352238/article/details/138424691?spm=1001.2014.3001.5501
但是上文jwt过期时间是由yml文件中配置的,比较不优雅,我们今天来用redis缓存token 的方法来进行 jwt的过期设置。
修改部分
我们把jwt过期时间来注释掉,实体类中的也注释掉
然后把创建jwt令牌的 创建方法参数也修改一下
如果这样设置不加修改的话,等于说我们登陆一次令牌就永不过期,下面 我们来思考 怎么把令牌加入redis 来进行缓存
思路分析
我们可以看我们的logincontroller方法,我们的方法中 是 如果是请求的登录接口 ,我们就对登录的用户名密码与数据库对应,如果登录用户密码正确,那么就生成一个token,然后后续的其他接口来进行访问的时候都会携带这个token ,如果用户名密码 不与数据库中的一致,那么就抛出异常
在此之中的逻辑,我们在什么时机加入redis缓存并且设置过期时间呢?
我们可以这样想,我们登录用户名密码正确的时候生成了token并且返回前端,之后请求都会携带token,那我们 可以在 生成token的时候,把token 加入redis缓存中并且设置一个过期时间,然后在拦截器 的实现那里,每次非登录请求的时候我们都访问redis 中的token数据,如果token数据过期,那么就抛异常,如果不过期就继续访问接口放行
具体实现
controller代码
@RestController
@Slf4j
@RequiredArgsConstructor
public class LoginController {
private final UserLoginService userLoginService;
private final JwtProperties jwtProperties;
private final RedisTemplate redisTemplate;
@PostMapping("/userLogin")
public Result userLogin( String username, String password) {
password=DigestUtils.md5DigestAsHex(password.getBytes());
LambdaQueryWrapper<UserLogin> userLoginLambdaQueryWrapper = new LambdaQueryWrapper<UserLogin>()
.eq(UserLogin::getUsername, username);
UserLogin userLogin = userLoginService.getOne(userLoginLambdaQueryWrapper);
if(userLogin==null && userLogin.getUsername().isEmpty()){
return Result.error("查询不到用户");
}
if (username.equals(userLogin.getUsername()) && password.equals(userLogin.getPassword())) {
//需要一个map集合 传什么 解析出来什么 一般传的是登录用户的id 我们传1
HashMap<String, Object> map = new HashMap<>();
map.put(MessageConstant.LOGIN_ID, userLogin.getId());
String token = JwtUntils.CreateJwt(map, jwtProperties.getSecretkey());
//设置redis缓存为1000天
redisTemplate.opsForValue().set(MessageConstant.TOKEN,token,1000,TimeUnit.DAYS);
return Result.success(token);
}
return Result.error("未知错误");
}
}
interceptor方法
@Component
@RequiredArgsConstructor
@Slf4j
public class JwtInterceptor implements HandlerInterceptor {
private final JwtProperties jwtProperties;
private final RedisTemplate redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//主要解析到请求头之后的token 之后 进行一次 的登录请求校验 如果不是登录请求 而是其他的方法 我们就进行放行
String requestURI = request.getRequestURI();
if (requestURI.contains("/userLogin")) {
return true;
}
//获取请求头的 token
// String token = request.getHeader(jwtProperties.getTokenname());
String redisToken = (String)redisTemplate.opsForValue().get(MessageConstant.TOKEN);
log.info("token:{}",redisToken);
if (redisToken != null ) {
//进行jwt的解析
try {
Claims claims = JwtUntils.parseJwt(redisToken, jwtProperties.getSecretkey());
//每次 访问其他资源的时候 都把token更新
redisTemplate.expire(MessageConstant.TOKEN, 1000, TimeUnit.DAYS);
String loginId = claims.get(MessageConstant.LOGIN_ID).toString();
ThreadContext.setCurrentId(Long.valueOf(loginId));
log.info("当前用户的id:{}", ThreadContext.getCurrentId());
return true;
} catch (Exception e) {
response.setStatus(401);
log.info("{}",e.getMessage());
return false;
}
}
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
}
下面我们进行接口测试
接口测试
我们先看我们redis中现在是没有存token的
我们进行登录
然后再去看我们redis中的token数据
过期时间是八千多万秒,然后我们随便进行一个查询员工的请求
再看redis中token的缓存时间
又变回来了