在上一篇中Redis实战之session共享,我们知道了通过Redis实现session共享了,那么token怎么续命呢?怎么刷新用户呢?本来咱们就通过拦截器来实现这两个功能。
登录拦截器优化:
先来看看现在拦截器情况:
拦截流程:
当拦截器拦截需要拦截到的url时候,才会在拦截器中更新用户token的过期时间。那如果,访问了不被拦截的路径,就不会给token续命的。这样就会导致用户token过期,而重新登录的。这样是不对的。
拦截了哪些路径?在config/MvcConfig中
当访问以上这些路径的是,就不会自动更新用户的token过期时间了。
优化:我们可以在现有拦截器签名价格拦截器:
将获取用户,存放threadLocal及刷新token放到新的拦截器中。
第一个拦截器就叫做:刷新token拦截器;第二个拦截器就叫做:用户拦截器
创建刷新token的拦截器:
import cn.hutool.core.bean.BeanUtil;
import com.hmdp.dto.UserDTO;
import com.hmdp.utils.UserHolder;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;
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;
import static com.hmdp.constants.RedisConstants.LOGIN_USER_TOKEN_KEY;
import static com.hmdp.constants.RedisConstants.LOGIN_USER_TOKEN_TTL;
/**
* @author 凯哥Java
* @description 刷新用户token的烂机器
* @company
*/
public class RefreshTokenInterceptor implements HandlerInterceptor {
private StringRedisTemplate stringRedisTemplate;
/**
* 因为这个类不能被spring管理,所以不能直接注入RedisTemplate对象。通过构造函数传递
*
* @param 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 (StringUtils.isEmpty(token)) {
return true;
}
//2:基于token获取redis中用户对象
String key = LOGIN_USER_TOKEN_KEY + token;
Map userMap = stringRedisTemplate.opsForHash().entries(key);
//3:判断
if (userMap.isEmpty()) {
return true;
}
//将map转对象
UserDTO user = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);
UserHolder.saveUser(user);
//刷新token的过期时间
stringRedisTemplate.expire(key, LOGIN_USER_TOKEN_TTL, TimeUnit.MINUTES);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserHolder.removeUser();
}
}
修改用户拦截器:
import com.hmdp.utils.UserHolder;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author 凯哥Java
* @description 登录拦击器
* @company
*/
public class UserInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//判断是否需要拦截
if (UserHolder.getUser() == null) {
response.setStatus(401);
return false;
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserHolder.removeUser();
}
}
修改MvcCofig。将两个拦截器添加进去,并设置拦截顺序:
import com.hmdp.interceptor.RefreshTokenInterceptor;
import com.hmdp.interceptor.UserInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
/**
* @author 凯哥Java
* @description mvn的配置-添加拦截器
* @company
*/
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Resource
private StringRedisTemplate stringRedisTemplate;
@Override
public void addInterceptors(InterceptorRegistry registry) {
//登录拦截器
registry.addInterceptor(new UserInterceptor())
.excludePathPatterns(
"/shop/**",
"/voucher/**",
"/shop-type/**",
"/upload/**",
"/blog/hot",
"/user/code",
"/user/login"
).order(1);
//刷新token拦截器
registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).addPathPatterns("/**").order(0);
}
}
领取专属 10元无门槛券
私享最新 技术干货