JWT是JSON WEB TOKEN的简写,常用于生成及校验Token。

常见的使用场景为:用户携带name和秘钥访问后端服务器,应用后端在校验通过后使用JWT生成并返回一串Token,后续用户只需要携带此Token就可以访问服务器,在此不多赘述。

本文目的是基于redis实现token自动更新其过期时间,在校验用户姓名和密码后使用JWT工具类生成会过期的Token,当用户携带此Token访问服务器后会自动延长其过期时间。

例如:用户A携带账户名及秘钥获取token,该token过期时间为2小时,过了1小时后用户再次携带该token访问系统,系统会自动将该token过期时间设置为此刻往后2小时候过期。

1、前提

1.1、JWT工具类
public class JwtUtil {

  public static final String JWT_ID = "dshsdhsdgjhjdsh";

  /**
   * jwt 加密解密密钥(可自行填写Base64加密)
   */
  private static final String JWT_SECRET = "ahsagsggfTwGGFff";

  /**
   * 创建JWT
   */
  public static String createJwt(Map claims, Long time) {
    //指定签名的时候使用的签名算法,也就是header那部分,jjwt已经将这部分内容封装好了。
    SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
    Date now = new Date(System.currentTimeMillis());

    SecretKey secretKey = generalKey();
    //下面就是在为payload添加各种标准声明和私有声明了,new一个JwtBuilder,设置jwt的body
    JwtBuilder builder = Jwts.builder()
            //如果有私有声明,一定要先设置这个自己创建的私有的声明,这个是给builder的claim赋值,一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明的
            .setClaims(claims)
            //设置jti(JWT ID):是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放攻击。
            .setId(JWT_ID)
            //iat: jwt的签发时间
            .setIssuedAt(now)
            //设置过期时间
            .setExpiration(new Date(System.currentTimeMillis() + time))
            //设置签名使用的签名算法和签名使用的秘钥
            .signWith(signatureAlgorithm, secretKey);
    return builder.compact();
  }

  /**
   * 验证jwt
   */
  public static Claims verifyJwt(String token) {
    //签名秘钥,和生成的签名的秘钥一模一样
    SecretKey key = generalKey();
    Claims claims;
    try {
      //得到DefaultJwtParser
      claims = Jwts.parser()
              //设置签名的秘钥
              .setSigningKey(key)
              .parseClaimsJws(token).getBody();
    } catch (Exception e) {
      claims = null;
    }//设置需要解析的jwt
    return claims;

  }

  /**
   * 刷新token并设置过期时间
   * @param token 旧的token
   * @param newExpirationInMillis 过期时间,单位毫秒
   * @return 新的jwt token
   */
  public static String updateTokenExpiration(String token, Long newExpirationInMillis) {
    SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
    SecretKey secretKey = generalKey();
    Claims claims = Jwts.parser()
            .setSigningKey(secretKey)
            .parseClaimsJws(token)
            .getBody();

    claims.setExpiration(new Date(System.currentTimeMillis()+newExpirationInMillis));
    return Jwts.builder()
            .setClaims(claims)
            .setId(JWT_ID)
            .signWith(signatureAlgorithm, secretKey)
            .compact();
  }


  /**
   * 由字符串生成加密key
   *
   * @return
   */
  public static SecretKey generalKey() {
    byte[] encodedKey = Base64.decodeBase64(JWT_SECRET);
    SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
    return key;
  }

}
1.2、Maven依赖
    io.jsonwebtoken
    jjwt
    0.9.1
1.3、配置过期时间及其他常量
private static final long EXPIRE_TIME = 7200 * 1000;
private static final String USER_NAME = "user_name";
private static final String SECRET = "password";
private static final String JWT_TOKEN_USERNAME = "jwt_token:username";

2、思路与流程

2.1、生成Token

步骤一:用户携带userName和Password访问后端接口,当校验通过后使用JWT工具类生成Token;

 //校验appId和秘钥
...
//如果校验通过则生成JWT
 HashMap jwtMap = new HashMap(5);
 jwtMap.put(USER_NAME, userName);
 jwtMap.put(SECRET, password);
 //生成JWT
 String jwt = JwtUtil.createJwt(jwtMap, EXPIRE_TIME);

步骤二:将生成Token及过期时间放入redis数据库

  String oldToken = (String) redisClient.get(JWT_TOKEN_USERNAME + USER_NAME);
  //判断是否存在旧的Token
  if (oldToken != null) {
      redisClient.delete(oldToken);
   }
   //多次获取token只生效最后一次
   redisClient.set(jwt, jwt, EXPIRE_TIME);
   redisClient.set(JWT_TOKEN_USERNAME + appId, jwt, EXPIRE_TIME);
2.2、校验Token
 String valueToken = (String) redisClient.get(token);
 if (valueToken == null) {
      //输出无效信息
     log.error("TOKEN:{}无效", token);
     //抛异常
    throw new Exception();
  } else {
  Claims claims = JwtUtil.verifyJwt(valueToken);
  if (claims == null) {
      log.error("TOKEN:{}已过期", token);
      throw new Exception();
  }
   String newToken = JwtUtil.updateTokenExpiration(valueToken, EXPIRE_TIME);
   log.info("刷新后的token为:{}", newToken);
   redisClient.set(token, newToken, EXPIRE_TIME);
   String appKey = (String) claims.get(USER_NAME);
   redisClient.expire(JWT_TOKEN_USERNAME + username, EXPIRE_TIME,TimeUnit.MILLISECONDS);
   return claims.get(USER_NAME);
        }

本站无任何商业行为
个人在线分享-虚灵IT资料分享 » Redis实现JWT(JSON Web TOKEN)自动延长TOKEN过期时间
E-->