HandlerInterceptor
阻挡所有请求
获取请求头中的token,基于token 获取redis中的用户
空的return ture 放行的原因 : 因为用户可能是访问不需要登陆的页面
package com.hmdp.utils;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.hmdp.dto.UserDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Slf4j
public class RefreshTokenInterceptor implements HandlerInterceptor {
private StringRedisTemplate stringRedisTemplate;
public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
/**
* 进到controller 之前登入效验
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取请求头中的token
String token = request.getHeader("authorization");
if(StrUtil.isBlank(token)){
return true;
}
String tokenKey = RedisConstants.LOGIN_USER_KEY + token;
// 基于token 获取redis中的用户
Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(tokenKey);
// entries() 原本就会判断 空的话返回null
// 判断用户是否存在
if(userMap.isEmpty()){
return true; // 空的也放行是因为用户可能是访问不需要登陆的页面
}
// 需要登入的请求则更新token TTL
// 将查询的Hash 转UserDTO
UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);
// 存在,保存用户信息到 ThreadLocal
// 在处理每个 HTTP 请求时,可以将用户身份信息存储在 ThreadLocal 中
// 然后在后续的处理逻辑中随时获取,而不必重复查询数据库或其他存储系统
UserHolder.saveUser(userDTO);
// 更新 token 存活时间
stringRedisTemplate.expire(tokenKey ,RedisConstants.CACHE_SHOP_TTL , TimeUnit.MINUTES);
// log.info("preHandle user={}",UserHolder.getUser());
// 放行
return true;
}
//用户业务执行完毕,销毁用户信息避免内存泄漏
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 移除用户
UserHolder.removeUser();
}
}
阻挡需要登陆的请求
从这个WebMvcConfigurer 注册的顺序来看是,1.RefreshTokenInterceptor 2.LoginInterceptor
LoginInterceptor 是拦截需要登录的请求,只需要判断是否有保存用户信息到 ThreadLocal即可
package com.hmdp.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
private StringRedisTemplate stringRedisTemplate;
public LoginInterceptor(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if(UserHolder.getUser()== null){
response.setStatus(401);
return false;
}
// 放行
return true;
}
}