1 基于Session实现登录

2. 集群的Session共享问题

3. 基于Redis实现共享session登录

4. 拦截器配置
用户有已登录和游客状态,对于已登录的用户,需要在其进行任意操作时刷新用户的token。对于游客我们要拦截一些特定的请求。对于这个需求,设置了两个拦截器来实现。
4.1 RefreshTokenInterceptor
该拦截器拦截所有请求,先根据键从redis中查看是否有用户信息,有则保存到ThreadLocal并刷新token,没有则直接放行。
java
public class RefreshTokenInterceptor implements HandlerInterceptor {
private StringRedisTemplate stringRedisTemplate;
public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1.获取请求头中的token
String token = request.getHeader("authorization");
if (StrUtil.isBlank(token)) {
return true;
}
// 2.基于token获取redis中的用户
String key = RedisConstants.LOGIN_USER_KEY + token;
Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);
// 3.判断用户是否存在
if (userMap.isEmpty()) {
return true;
}
//5.将查询到的Hsah数据转换为UserDTO对象
UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);
// 6.存在,保存用户信息到ThreadLocal
UserHolder.saveUser(userDTO);
// 7.刷新token的有效期
stringRedisTemplate.expire(key, RedisConstants.LOGIN_USER_TTL, TimeUnit.MINUTES);
// 8.放行
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserHolder.removeUser();
}
}
4.2 LoginInterceptor
该拦截器拦截特定的请求,未登陆的游客不能访问某些接口。
java
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//判断是否需要拦截(ThreadLocal中是否有用户)
if (UserHolder.getUser() == null) {
//没有,需要拦截,设置状态码
response.setStatus(401);
return false;
}
// 有用户,则放行
return true;
}
}
4.3 MvcConfig配置类
在该配置类中注册拦截器,设置拦截器的顺序以及限制访问的接口。
java
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 刷新token拦截器
registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).addPathPatterns("/**").order(0);
// 登录拦截器
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**")
.excludePathPatterns(
"/user/code",
"/user/login",
"/blog/hot",
"/shop/**",
"/shop-type/**",
"/upload/**",
"/voucher/**"
).order(1);
}
}