采用redis+ThreadLocal获取全局的登录用户信息(二)增加token快失效时刷新
在寫token登錄的時(shí)候,發(fā)現(xiàn)cookie中的token到時(shí)自動(dòng)失效,如果此時(shí)有人正在操作,非常影響體驗(yàn),于是增加了一個(gè)token快失效時(shí)刷新token的功能。下面代碼重點(diǎn)就在TokenTool類中的時(shí)間判斷
1.先寫一個(gè)tokenTime的工具類
public class TokenTime {/*1小時(shí)以內(nèi),token有效1-2小時(shí)之內(nèi),token進(jìn)行刷新2小時(shí)之后,token失效*///cookie和redis中token超過一小時(shí)刷新public static final int TokenOutTime_hour=1;//cookie瀏覽器保存token有效期設(shè)為2小時(shí)public static final int cookie_time=60 * 60 * 2;//redis保存token有效期設(shè)為2小時(shí)public static final int redis_time=60 * 60 * 2;}2.再寫一個(gè)TokenTool的工具類
public class TokenTool {//生成Tokenpublic String CreateToken(){LocalDateTime now=LocalDateTime.now();//年月日時(shí)分秒毫秒Date date =new Date();String uuid = UUID.randomUUID().toString();String token=uuid+date.getTime();return token;}//判斷token時(shí)間戳是否需要刷新public boolean tokenOutTime(String OldToken) throws ParseException {//年月日時(shí)分秒毫秒Date date =new Date();SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");int Oldmax=OldToken.length();long Newtime=date.getTime();long Oldtime = Long.parseLong(OldToken.substring(36, Oldmax));/*給cookie中的時(shí)間加上一小時(shí),1小時(shí)以內(nèi),token有效1-2小時(shí)之內(nèi),token進(jìn)行刷新2小時(shí)之后,token失效*/Long OldLoseTime= addDate(Oldtime, TokenTime.TokenOutTime_hour);Date NewDate = new Date(Newtime);Date oldDate = new Date(OldLoseTime);String st= simpleDateFormat.format(oldDate);String en= simpleDateFormat.format(NewDate);Date oldTokenTime=simpleDateFormat.parse(st);Date newTokenTime=simpleDateFormat.parse(en);if (oldTokenTime.before(newTokenTime)){System.out.println("token需要刷新");return true;}else{System.out.println("token不需要刷新");return false;}}//給時(shí)間戳增加時(shí)間public static Long addDate(long time,long hour) throws ParseException {hour = hour*1*60*60*1000; // 要加上的天數(shù)轉(zhuǎn)換成毫秒數(shù)time+=hour; // 相加得到新的毫秒數(shù)return time; // 將毫秒數(shù)轉(zhuǎn)換成日期} }?
3.然后寫一個(gè)登錄接口,代碼已經(jīng)假設(shè)你從數(shù)據(jù)庫(kù)拿到了用戶信息保存在變量userinfo中,將token返回給瀏覽器保存,并將token和userinfo保存在redis中。
@Resourceprivate RedisTemplate redisTemplate;@RequestMapping("/login")public R token(HttpServletRequest request, HttpServletResponse response) {//假設(shè)此時(shí)已經(jīng)從數(shù)據(jù)庫(kù)獲取到用戶信息在userinfoTokenTool token =new TokenTool();String cretoken=token.CreateToken();//生成tokenCookie cookie=new Cookie("tokenUser",cretoken);cookie.setMaxAge(TokenTime.cookie_time);//有效期設(shè)為2小時(shí)//設(shè)置路徑cookie.setPath("/");//響應(yīng)回游覽器response.addCookie(cookie);RedisCache redis=new RedisCache(redisTemplate);redis.set(cretoken,userinfo,TokenTime.redis_time);//有效期設(shè)為2小時(shí)return R.ok(userinfo,"登錄成功");}4.新建一個(gè)類型,這個(gè)是全局線程。當(dāng)用戶信息經(jīng)過token驗(yàn)證從redis拿出來(lái)之后要保存在這個(gè)里面,想用的時(shí)候從這個(gè)里面拿取就行了。
public class UserThreadLocal {private static ThreadLocal<User> userThread =new ThreadLocal<User>();public static void set(User user){userThread.set(user);}public static User get(){return userThread.get();}//防止內(nèi)存泄漏public static void remove(){userThread.remove();} }5.新建一個(gè)攔截器,業(yè)務(wù)邏輯是 獲取瀏覽器token,再?gòu)膔edis獲取userinfo,將userinfo保存在UserThreadLocal線程中。
@Configuration public class LoginInterceptor implements HandlerInterceptor {@Resourceprivate RedisTemplate redisTemplate;@Autowiredprivate static ObjectMapper objectMapper = new ObjectMapper();//在執(zhí)行COntroller方法之前執(zhí)行/*** boolean 表示是否放行* true:放行 用戶可以跳轉(zhuǎn)頁(yè)面* false:攔截 之后給定重定向路徑** 業(yè)務(wù)邏輯:* 1.判斷用戶客戶端是否有Cookie/token數(shù)據(jù)* 如果用戶沒有token則重定向到用戶登陸頁(yè)面* 2.如果用戶token中有數(shù)據(jù),則從redis緩存中獲取數(shù)據(jù)* 如果redis中數(shù)據(jù)為null,則重定向到用戶登陸頁(yè)面* 3.如果reids中有數(shù)據(jù),則放行請(qǐng)求.*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {String token = "";//獲取Cookie數(shù)據(jù)Cookie[] cookies = request.getCookies();for (Cookie cookie : cookies) {if("tokenUser".equals(cookie.getName())){token = cookie.getValue();break;}}//判斷Cookie是否為nullif(!StringUtils.isEmpty(token)){//檢測(cè)緩存中是否有該數(shù)據(jù)RedisCache redis=new RedisCache(redisTemplate);Object userinfo = redis.get(token);TokenTool cretoken =new TokenTool();if(cretoken.tokenOutTime(token)){String cookiesAndRedisToken=cretoken.CreateToken();Cookie cookie=new Cookie("tokenUser",cookiesAndRedisToken);cookie.setMaxAge(TokenTime.cookie_time);//有效期設(shè)為2小時(shí)//設(shè)置路徑cookie.setPath("/");//響應(yīng)回游覽器response.addCookie(cookie);redis.set(cookiesAndRedisToken,userinfo,TokenTime.redis_time);//有效期設(shè)為2小時(shí)if(!StringUtils.isEmpty(userinfo)){//將userJSON轉(zhuǎn)化為User對(duì)象User user= (User) userinfo;UserThreadLocal.set(user);//用戶已經(jīng)登陸 放行請(qǐng)求return true;}}else{if(!StringUtils.isEmpty(userinfo)){//將userJSON轉(zhuǎn)化為User對(duì)象User user= (User) userinfo;UserThreadLocal.set(user);//用戶已經(jīng)登陸 放行請(qǐng)求return true;}}}//表示用戶沒有登陸response.sendRedirect("/login.html");return false;}//執(zhí)行完業(yè)務(wù)邏輯后攔截@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {// TODO Auto-generated method stub}//返回頁(yè)面之前攔截@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {//將ThreadLocal數(shù)據(jù)清空UserThreadLocal.remove();}}6.新建一個(gè)攔截器配置類,設(shè)置要訪問攔截器的路徑,開放登錄接口和靜態(tài)資源接口,其他都配置成要訪問攔截器
@Configuration public class InterceptorConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry){//添加對(duì)用戶未登錄的攔截器,并添加排除項(xiàng)registry.addInterceptor(loginInterceptor).addPathPatterns("/**")//攔截所有.excludePathPatterns("/js/**","/dist/images/**")//排除樣式、腳本、圖片等資源文件.excludePathPatterns("/login")//排除登錄.excludePathPatterns("/","/index");} }7.獲取用戶信息
@RequestMapping("/getuserinfo")public R getuserinfo() {User user = UserThreadLocal.get();System.out.println(user);return R.ok(user,"獲取用戶信息成功");}?
總結(jié)
以上是生活随笔為你收集整理的采用redis+ThreadLocal获取全局的登录用户信息(二)增加token快失效时刷新的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 百度app如何设置青少年模式(百度产品大
- 下一篇: Layui中设置公共的全局变量接口