shiro + jwt 实现 rememberMe 超时功能

匿名 (未验证) 提交于 2019-12-02 21:53:52

  上一篇提出, 通过修改 rememberMe 的编码来实现 rememberMe的功能的设想, 事后我去尝试实现了一番, 发现太麻烦, 还是不要那么做吧. 程序还是要越简单越好.

  so, 换条路试试:

实现:

一. jwt帮助类

import ccdc.zykt.model.vo.UserExt; import io.jsonwebtoken.Jwt; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.impl.DefaultClaims; import org.apache.commons.lang.time.DateUtils; import org.apache.shiro.codec.Base64;  import java.util.Date;  public class JWTUtil {     private static final String KEY = Base64.encodeToString("jwt.key".getBytes());      public static String createJWT(String token) {         Date now = new Date();         return Jwts.builder()                 .setSubject(token)                 .setIssuedAt(now)                 .setExpiration(DateUtils.addMinutes(now, 1))                 .signWith(SignatureAlgorithm.HS512, KEY).compact();     }      public static String createJWT(String token, int amount){         Date now = new Date();         return Jwts.builder().setSubject(token).setIssuedAt(now).setExpiration(DateUtils.addHours(now, amount)).signWith(SignatureAlgorithm.HS512, KEY).compact();     }      public static boolean validate(String jwt){         try {              Jwts.parser().setSigningKey(KEY).parse(jwt);              return true;         } catch (Throwable t) {             return false;         }     }      public static String validateJWT(String jwt) {         try {             Jwt parse = Jwts.parser().setSigningKey(KEY).parse(jwt);             DefaultClaims body = (DefaultClaims) parse.getBody();             String phone = body.getSubject();             return phone;         } catch (Throwable t) {             return null;         }     } }

二. 改写HeaderRememberMeManager类

package ccdc.zykt.web.shiro.headtoken;  import ccdc.zykt.web.util.JWTUtil; import com.google.common.base.Strings; import org.apache.commons.compress.utils.ByteUtils; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.codec.Base64; import org.apache.shiro.mgt.AbstractRememberMeManager; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.SubjectContext; import org.apache.shiro.web.servlet.ShiroHttpServletRequest; import org.apache.shiro.web.subject.WebSubjectContext; import org.apache.shiro.web.util.WebUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.util.StringUtils;  import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.List;  /**  * 将remember放到响应头中去, 然后从请求头中解析  * @author: elvin  * @time: 2018-07-05 15:11  * @desc:  **/ public class HeaderRememberMeManager extends AbstractRememberMeManager {      private static final transient Logger log = LoggerFactory.getLogger(HeaderRememberMeManager.class);      // header 中 固定使用的 key     public static final String DEFAULT_REMEMBER_ME_HEADER_NAME = "remember-me";      @Override     protected void rememberSerializedIdentity(Subject subject, byte[] serialized) {         if (!WebUtils.isHttp(subject)) {             if (log.isDebugEnabled()) {                 String msg = "Subject argument is not an HTTP-aware instance.  This is required to obtain a servlet request and response in order to set the rememberMe cookie. Returning immediately and ignoring rememberMe operation.";                 log.debug(msg);             }          } else {             HttpServletResponse response = WebUtils.getHttpResponse(subject);              String base64 = Base64.encodeToString(serialized);              base64 = JWTUtil.createJWT(base64);              // 设置 rememberMe 信息到 response header 中             response.setHeader(DEFAULT_REMEMBER_ME_HEADER_NAME, base64);         }     }      private boolean isIdentityRemoved(WebSubjectContext subjectContext) {         ServletRequest request = subjectContext.resolveServletRequest();         if (request == null) {             return false;         } else {             Boolean removed = (Boolean) request.getAttribute(ShiroHttpServletRequest.IDENTITY_REMOVED_KEY);             return removed != null && removed;         }     }      @Override     protected byte[] getRememberedSerializedIdentity(SubjectContext subjectContext) {         if (!WebUtils.isHttp(subjectContext)) {             if (log.isDebugEnabled()) {                 String msg = "SubjectContext argument is not an HTTP-aware instance.  This is required to obtain a servlet request and response in order to retrieve the rememberMe cookie. Returning immediately and ignoring rememberMe operation.";                 log.debug(msg);             }              return null;         } else {             WebSubjectContext wsc = (WebSubjectContext) subjectContext;             if (this.isIdentityRemoved(wsc)) {                 return null;             } else {                 HttpServletRequest request = WebUtils.getHttpRequest(wsc);                 // 在request header 中获取 rememberMe信息                 String base64 = request.getHeader(DEFAULT_REMEMBER_ME_HEADER_NAME);                 if ("deleteMe".equals(base64)) {                     return null;                 } else if (base64 != null) {                     base64 = JWTUtil.validateJWT(base64);                     if(Strings.isNullOrEmpty(base64)){                         return null;                     }                      base64 = this.ensurePadding(base64);                     if (log.isTraceEnabled()) {                         log.trace("Acquired Base64 encoded identity [" + base64 + "]");                     }                      byte[] decoded = Base64.decode(base64);                     if (log.isTraceEnabled()) {                         log.trace("Base64 decoded byte array length: " + (decoded != null ? decoded.length : 0) + " bytes.");                     }                      return decoded;                 } else {                     return null;                 }             }         }     }      private String ensurePadding(String base64) {         int length = base64.length();         if (length % 4 != 0) {             StringBuilder sb = new StringBuilder(base64);              for (int i = 0; i < length % 4; ++i) {                 sb.append('=');             }              base64 = sb.toString();         }          return base64;     }      @Override     protected void forgetIdentity(Subject subject) {         if (WebUtils.isHttp(subject)) {             HttpServletRequest request = WebUtils.getHttpRequest(subject);             HttpServletResponse response = WebUtils.getHttpResponse(subject);             this.forgetIdentity(request, response);         }      }      @Override     public void forgetIdentity(SubjectContext subjectContext) {         if (WebUtils.isHttp(subjectContext)) {             HttpServletRequest request = WebUtils.getHttpRequest(subjectContext);             HttpServletResponse response = WebUtils.getHttpResponse(subjectContext);             this.forgetIdentity(request, response);         }     }      private void forgetIdentity(HttpServletRequest request, HttpServletResponse response) {         //设置删除标示         response.setHeader(DEFAULT_REMEMBER_ME_HEADER_NAME, "deleteMe");     } }

结果展示:

1. 登录之后, 使用postmen 尝试访问

2. 耐心等待1分钟, 然后再去访问这个接口试试

试验证明, 还是可行的.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!