在上一篇中Redis實(shí)戰(zhàn)之session共享檐蚜,我們知道了通過Redis實(shí)現(xiàn)session共享了魄懂,那么token怎么續(xù)命呢?怎么刷新用戶呢闯第?本來咱們就通過攔截器來實(shí)現(xiàn)這兩個(gè)功能市栗。
登錄攔截器優(yōu)化:
先來看看現(xiàn)在攔截器情況:
攔截流程:
當(dāng)攔截器攔截需要攔截到的url時(shí)候,才會(huì)在攔截器中更新用戶token的過期時(shí)間咳短。那如果填帽,訪問了不被攔截的路徑,就不會(huì)給token續(xù)命的诲泌。這樣就會(huì)導(dǎo)致用戶token過期盲赊,而重新登錄的。這樣是不對(duì)的敷扫。
攔截了哪些路徑哀蘑?在config/MvcConfig中
當(dāng)訪問以上這些路徑的是,就不會(huì)自動(dòng)更新用戶的token過期時(shí)間了葵第。
優(yōu)化:我們可以在現(xiàn)有攔截器簽名價(jià)格攔截器:
將獲取用戶绘迁,存放threadLocal及刷新token放到新的攔截器中。
第一個(gè)攔截器就叫做:刷新token攔截器卒密;第二個(gè)攔截器就叫做:用戶攔截器
創(chuàng)建刷新token的攔截器:
<pre class="brush:as3;toolbar:false" style="margin: 0.5em 0px; padding: 0.4em 0.6em; border-radius: 8px; background: rgb(248, 248, 248);">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的爛機(jī)器
-
@company
*/
public class RefreshTokenInterceptor implements HandlerInterceptor {private StringRedisTemplate stringRedisTemplate;
/**
- 因?yàn)檫@個(gè)類不能被spring管理缀台,所以不能直接注入RedisTemplate對(duì)象。通過構(gòu)造函數(shù)傳遞
- @param stringRedisTemplate
*/
public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {
this.stringRedisTemplate = stringRedisTemplate;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//1:從請(qǐng)求中獲取到token
String token = request.getHeader("authorization");
if (StringUtils.isEmpty(token)) {
return true;
}
//2:基于token獲取redis中用戶對(duì)象
String key = LOGIN_USER_TOKEN_KEY + token;
Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);
//3:判斷
if (userMap.isEmpty()) {
return true;
}
//將map轉(zhuǎn)對(duì)象
UserDTO user = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);
UserHolder.saveUser(user);
//刷新token的過期時(shí)間
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();
}
}
</pre>
修改用戶攔截器:
<pre class="brush:as3;toolbar:false" style="margin: 0.5em 0px; padding: 0.4em 0.6em; border-radius: 8px; background: rgb(248, 248, 248);">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();
}
}
</pre>
修改MvcCofig哮奇。將兩個(gè)攔截器添加進(jìn)去膛腐,并設(shè)置攔截順序:
<pre class="brush:as3;toolbar:false" style="margin: 0.5em 0px; padding: 0.4em 0.6em; border-radius: 8px; background: rgb(248, 248, 248);">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);
}
}
</pre>