JWT的TOKEN续期功能
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JWT的TOKEN续期功能相关的知识,希望对你有一定的参考价值。
参考技术A JWT里有一个关键的东东,就是续期TOKEN,即TOKEN快过期时,刷新一个新的TOKEN给客户端.办法如下:
1.后端生成TOKEN
importcom.starmark.core.shiro.model.SecurityUser;importcom.starmark.core.shiro.model.UserLoginToken;importcom.starmark.core.shiro.util.JWTUtil;importorg.apache.commons.lang3.BooleanUtils;importorg.apache.commons.lang3.StringUtils;importorg.apache.shiro.authc.AuthenticationException;importorg.apache.shiro.authc.AuthenticationToken;importorg.apache.shiro.subject.Subject;importorg.apache.shiro.web.filter.authc.AuthenticatingFilter;importorg.apache.shiro.web.util.WebUtils;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.web.bind.annotation.RequestMethod;importjavax.servlet.ServletRequest;importjavax.servlet.ServletResponse;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.time.LocalDateTime;importjava.time.ZoneId;importjava.util.Date;importjava.util.Objects;publicclassJwtAuthFilterextendsAuthenticatingFilterprivatefinalLoggerlog=LoggerFactory.getLogger(JwtAuthFilter.class);//10分钟后刷新tokenprivatestaticfinalinttokenRefreshInterval=60*10;@OverrideprotectedbooleanpreHandle(ServletRequestrequest,ServletResponseresponse)throwsExceptionHttpServletRequesthttpServletRequest=WebUtils.toHttp(request);if(httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name()))//对于OPTION请求做拦截,不做token校验returnfalse;returnsuper.preHandle(request,response);@OverrideprotectedvoidpostHandle(ServletRequestrequest,ServletResponseresponse)request.setAttribute("jwtShiroFilter.FILTERED",true);@OverrideprotectedbooleanisAccessAllowed(ServletRequestrequest,ServletResponseresponse,ObjectmappedValue)if(this.isLoginRequest(request,response))returntrue;BooleanafterFiltered=(Boolean)(request.getAttribute("jwtShiroFilter.FILTERED"));if(BooleanUtils.isTrue(afterFiltered))returntrue;booleanallowed=false;tryallowed=executeLogin(request,response);catch(IllegalStateExceptione)//not found any tokenlog.error("Not found any token");catch(Exceptione)log.error("Error occurs when login",e);returnallowed||super.isPermissive(mappedValue);@OverrideprotectedAuthenticationTokencreateToken(ServletRequestservletRequest,ServletResponseservletResponse)StringjwtToken=getAuthzHeader(servletRequest);if(StringUtils.isNotBlank(jwtToken)&&!JWTUtil.isTokenExpired(jwtToken))returnUserLoginToken.buildPassword(jwtToken,null,"jwt");returnnull;@OverrideprotectedbooleanonAccessDenied(ServletRequestservletRequest,ServletResponseservletResponse)throwsExceptionHttpServletResponsehttpResponse=WebUtils.toHttp(servletResponse);httpResponse.sendRedirect("/unauth");returnfalse;@OverrideprotectedbooleanonLoginSuccess(AuthenticationTokentoken,Subjectsubject,ServletRequestrequest,ServletResponseresponse)HttpServletResponsehttpResponse=WebUtils.toHttp(response);if(tokeninstanceofUserLoginToken&&"jwt".equalsIgnoreCase(((UserLoginToken)token).getLoginType()))UserLoginTokenjwtToken=(UserLoginToken)token;booleanshouldRefresh=shouldTokenRefresh(Objects.requireNonNull(JWTUtil.getIssuedAt(jwtToken.getUsername())));if(shouldRefresh)//生成新的TOKENSecurityUseruser=(SecurityUser)subject.getPrincipal();StringnewToken=JWTUtil.sign(user.getUserInfo().getId());httpResponse.setHeader("x-auth-token",newToken);returntrue;@OverrideprotectedbooleanonLoginFailure(AuthenticationTokentoken,AuthenticationExceptione,ServletRequestrequest,ServletResponseresponse)log.error("Validate token fail, token:, error:",token.toString(),e.getMessage());returnfalse;/**
* 获取TOKEN
* @param request 请求
* @return token
*/privateStringgetAuthzHeader(ServletRequestrequest)HttpServletRequesthttpRequest=WebUtils.toHttp(request);Stringheader=httpRequest.getHeader("x-auth-token");returnStringUtils.removeStart(header,"Bearer ");/**
* 判断是否需要刷新TOKEN
* @param issueAt token签发日期
* @return 是否需要刷新TOKEN
*/privatebooleanshouldTokenRefresh(DateissueAt)LocalDateTimeissueTime=LocalDateTime.ofInstant(issueAt.toInstant(),ZoneId.systemDefault());returnLocalDateTime.now().minusSeconds(tokenRefreshInterval).isAfter(issueTime);
原签发TOKEN后10分钟后刷新新的TOKEN
2.前端获取TOKEN
// 拦截响应response,并做一些错误处理axios.interceptors.response.use((response)=>if(response.status===200&&response.data&&response.data.code===401)//console.log(window.location.origin);window.location.href=window.location.origin+window.location.pathname+'#/login';//获取返回的TOKENconsttoken=response.headers['x-auth-token'];if(token)//将续期的TOKEN存起来localStorage.setItem("token",token);// 这里是填写处理信息returnresponse;,(err)=>// 这里是返回状态码不为200时候的错误处理console.log(err);if(err&&err.response)switch(err.response.data.code)case400:err.message='请求错误';break;case401:err.message='未授权,请登录';break;case403:err.message='无权限';break;case404:err.message=`请求地址出错: $err.response.config.url`;break;case408:err.message='请求超时';break;case500:err.message='服务器内部错误';break;case501:err.message='服务未实现';break;case502:err.message='网关错误';break;case503:err.message='服务不可用';break;case504:err.message='网关超时';break;case505:err.message='HTTP版本不受支持';break;default:Vue.prototype.$message.error(err.response.data.msg!=null?err.response.data.msg:err.message);returnPromise.reject(err));
注意一点,需要通过过滤器调整FITLER,增加Access-Control-Expose-Headers的输出,否则无法获取response中的header.
至此,JWT的TOKEN续期功能完成.
JWT 登录认证 + Token 自动续期方案,写得太好了!
作者:何甜甜在吗 链接:https://juejin.cn/post/6932702419344162823 过去这段时间主要负责了项目中的用户管理模块,用户管理模块会涉及到加密及认证流程,加密已经在前面的文章中介绍了,可以阅读用户管理模块:如何保证用户数据安全。 今天就来讲讲认证功能的技术选型及实
以上是关于JWT的TOKEN续期功能的主要内容,如果未能解决你的问题,请参考以下文章
JWT 登录认证 + Token 自动续期方案,写得太好了!
JWT 登录认证 + Token 自动续期方案,写得太好了!
JWT 实现登录认证 + Token 自动续期方案,这才是正确的使用姿势!