Redis实现JWT(JSON Web TOKEN)自动延长TOKEN过期时间

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<String, Object> 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依赖
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>
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<String, Object> 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);
        }

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
JWTRedis 都可以用于实现 Token 校验,但具体的实现方式有所不同,下面分别介绍一下它们的优劣。 JWT 实现 Token 校验的优点: 1. 无状态:JWT 实现 Token 校验时不需要在服务器端存储任何信息,这样可以减轻服务器的负担,提高系统的性能。 2. 轻量级:JWT Token 的体积较小,可以减少网络传输的开销。 3. 可扩展性:JWT 可以很容易地与其他技术集成,如 OAuth、SAML 等,可以实现单点登录和跨域身份验证。 JWT 实现 Token 校验的缺点: 1. 无法注销:一旦颁发了 JWT,就无法撤回或注销,除非等到 JWT 过期或更改密钥。 2. 密钥管理困难:JWT 的安全性依赖于密钥的保护,如果密钥泄露或被攻击者获取,就可能会导致系统的安全问题。 3. 数据量较大:由于 JWT 包含了用户信息和签名等信息,因此数据量较大,可能会影响网络传输的性能。 Redis 实现 Token 校验的优点: 1. 数据存储在内存中:Redis 的数据存储在内存中,可以快速地对 Token 进行校验。 2. 高可用性:Redis 支持数据复制和故障转移,可以保证系统的高可用性。 3. 可扩展性:Redis 支持分布式部署和数据复制,可以实现数据的高可用和扩展性。 Redis 实现 Token 校验的缺点: 1. 数据存储成本高:Redis 的数据存储在内存中,如果数据量过大,可能会导致内存不足的问题。 2. 数据持久化成本高:Redis 的数据持久化可能会影响系统的性能,尤其是在大数据量或高并发的情况下。 3. 高可用性需要额外配置:Redis 的高可用性需要额外的配置和维护,可能会增加运维的成本。 综上所述,JWTRedis 都有其优点和缺点,具体的选择应根据具体的场景和需求进行考虑。如果需要实现无状态的 Token 校验并且数据量较小,可以考虑使用 JWT;如果需要实现高可用的 Token 校验并且数据量较大,可以考虑使用 Redis

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值