关于token:JWT工具类

40次阅读

共计 5356 个字符,预计需要花费 14 分钟才能阅读完成。

工具开源地址

    欢送大家搜寻“小猴子的技术笔记”关注我的公众号,有问题能够及时和我交换。

    之前咱们曾经理解到了什么是 JWT 以及 JWT 的长处,那么怎么在我的项目中应用到 JWT 呢?首先咱们须要在 maven 的我的项目中引入 JWT 的依赖:


<dependency>
  <groupId>com.auth0</groupId>
  <artifactId>java-jwt</artifactId>
  <version>3.12.0</version>
</dependency>

    胜利引入 jar 包之后就能够进行 token 的生成了。之后须要指定一个加密的算法,也就是须要你本人提供一个秘钥串来进行加密。你能够把它了解为之前做 MD5 加密的时候加上的盐值。

Algorithm algorithm = Algorithm.HMAC256("this is your secret")

    咱们有十种算法能够抉择:

    而后咱们就能够利用 jar 包中的办法,创立一个 token 并且附带上签名,之后就可能失去一个残缺的 token 令牌。


public static void main(String[] args) {Algorithm algorithm = Algorithm.HMAC256("this is your secret");
    String token = JWT.create().sign(algorithm);
    System.out.println(token);
}
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.e30.svmNHFYzrAj6USTjLekz3CTFyEdmpRkE8A8x3CbPe1Q

    这仅仅是一个简略的 token 的生成,有的时候咱们还想在 token 中传递咱们的信息,就能够应用上面这个办法:

public static void main(String[] args) {Algorithm algorithm = Algorithm.HMAC256("this is your secret");
    String token = JWT.create().withClaim("name", "小猴子").sign(algorithm);
    System.out.println(token);
}

    如果你有很多条件须要传递就能够“withClaim()”多个值。须要留神的是:这里请不要传递敏感的信息免得 token 被破解,信息泄露。

    咱们在开发中一个 token 必定不可能始终应用,肯定有个过期工夫。那么在 JWT 中怎么定义 token 的过期工夫呢?JWT 内置了为咱们设置 token 的过期工夫策略,官网给提供了一个“withExpireAt()”的办法。须要传递一个日期参数来指定过期工夫。

public static void main(String[] args) {Algorithm algorithm = Algorithm.HMAC256("this is your secret");
    JWTCreator.Builder builder = JWT.create().withClaim("name", "小猴子");
    String token = builder.withExpiresAt(new Date(System.currentTimeMillis() + 2000)).sign(algorithm);
    System.out.println(token);
}

    生成 token:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi5bCP54y05a2QIiwiZXhwIjoxNjEwODgzOTEzfQ.sAqi1xhajwKCxuv5sx8EwlcpbflsJs-k-67Nqr8PSYg

    下面咱们自定义了过期的工夫,是以后工夫 +2000 毫秒之后过期,也就是 2 秒之后过期。那么怎么来查看 token 是否曾经过期呢?咱们须要用到 token 的校验:

public static void main(String[] args) {Algorithm algorithm = Algorithm.HMAC256("this is your secret");
    JWTVerifier verifier = JWT.require(algorithm).build();
    DecodedJWT decoded = verifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi5bCP54y05a2QIiwiZXhwIjoxNjEwODgzOTEzfQ.sAqi1xhajwKCxuv5sx8EwlcpbflsJs-k-67Nqr8PSYg");
    System.out.println(decoded.getPayload());
}

    期待两秒之后在执行,你会发现它抛出如下的错误信息:

Exception in thread "main" com.auth0.jwt.exceptions.TokenExpiredException: The Token has expired on Sun Jan 17 19:45:13 CST 2021.
  at com.auth0.jwt.JWTVerifier.assertDateIsFuture(JWTVerifier.java:403)
  at com.auth0.jwt.JWTVerifier.assertValidDateClaim(JWTVerifier.java:394)
  at com.auth0.jwt.JWTVerifier.verifyClaimValues(JWTVerifier.java:314)
  at com.auth0.jwt.JWTVerifier.verifyClaims(JWTVerifier.java:303)
  at com.auth0.jwt.JWTVerifier.verify(JWTVerifier.java:288)
  at com.auth0.jwt.JWTVerifier.verify(JWTVerifier.java:271)
  at com.monkeybrother.jwt.utils.JwtUtil.main(JwtUtil.java:65)

    通过查看 JWT 的源码能够发现,JWT 给咱们提供了 5 中 token 校验的时候会抛出来的异样信息:

    咱们晓得 token 保留在客户端,相比于传统的 token 过期删除 token,JWT 的过期工夫是怎么管制的呢?它是将工夫设置为一个 ”claim” 而后在解析的时候解析这个“claim”通过拿到字段和以后工夫进行比拟。

    程序报异样是不够敌对的,咱们能够对异样进行捕捉,而后自定义咱们捕捉到的异样信息。于是咱们的校验 token 的办法能够进行更改成如下:

public static void main(String[] args) {
    try {Algorithm algorithm = Algorithm.HMAC256("this is your secret");
        JWTVerifier verifier = JWT.require(algorithm).build();
        DecodedJWT decoded = verifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi5bCP54y05a2QIiwiZXhwIjoxNjEwODgzOTEzfQ.sAqi1xhajwKCxuv5sx8EwlcpbflsJs-k-67Nqr8PSYg");
    } catch (AlgorithmMismatchException e) {System.out.println("token 算法不统一");
    } catch (InvalidClaimException e) {System.out.println("有效的 token 申明");
    } catch (JWTDecodeException e) {System.out.println("token 解码异样");
    } catch (SignatureVerificationException e) {System.out.println("token 签名有效");
    } catch (TokenExpiredException e) {System.out.println("token 已过期");
    } catch (Exception e) {System.out.println("其余异样");
    }
}

    如果 token 校验非法,咱们就能够从 token 中获取咱们之前设置的“claim”:


DecodedJWT decodedJWT = JWT.require(algorithm).build().verify(token);
public static void main(String[] args) {Algorithm algorithm = Algorithm.HMAC256("this is your secret");
    JWTCreator.Builder builder = JWT.create().withClaim("name", "小猴子");
    String token = builder.withExpiresAt(new Date(System.currentTimeMillis() + 2000000)).sign(algorithm);
    DecodedJWT decodedJWT = JWT.require(algorithm).build().verify(token);
    System.out.println(decodedJWT.getClaim("name").asString());
}

    对于咱们想要设置的“claim”总不能一个一个的增加吧,咱们能够封装一个办法对咱们想要增加的信息进行一次批量的增加。我这里给简略封装了一个工具类:

**
 * @Desc jwt 工具类
 * @Author houry
 * @Date 2021/1/5 10:09
 **/
public class JwtUtil {
    /**
     * 秘钥:须要妥善保留,一旦泄露 token 有可能被破解
     */
    private static final String SECRET = "#$@!FX()!JF%JS$KLS*KFH##%#QPCIXMSJ";
    /**
     * 签名算法:举荐应用 HMAC256
     */
    private static final Algorithm ALGORITHM = Algorithm.HMAC256(SECRET);

    /**
     * 设置默认过期工夫 1000*60*60=3600000=1h
     */
    private static final Long EXPIRE_DATE = 3600000L;

    /**
     * 获取 token 信息
     *
     * @param claimMap 自定义的条件
     * @return token 令牌
     */
    public static String getToken(Map<String, String> claimMap) {return getToken(claimMap, EXPIRE_DATE);
    }

    /**
     * @param claimMap 自定义条件
     * @param expire   过期工夫 单位:毫秒
     * @return token 令牌
     */
    public static String getToken(Map<String, String> claimMap, Long expire) {JWTCreator.Builder builder = JWT.create();
        claimMap.forEach(builder::withClaim);
        builder.withExpiresAt(new Date(System.currentTimeMillis() + expire));
        return builder.sign(ALGORITHM);
    }

    /**
     * 获取 DecodedJWT
     *
     * @param token token 令牌
     * @return DecodedJWT
     */
    public static DecodedJWT getDecodedJWT(String token) {return JWT.require(ALGORITHM).build().verify(token);
    }

    /**
     * 获取 DecodedJWT
     *
     * @param algorithm 指定算法
     * @param token     token 令牌
     * @return DecodedJWT
     */
    public static DecodedJWT getDecodedJWT(Algorithm algorithm, String token) {return JWT.require(algorithm).build().verify(token);
    }
}

    留神:这里仅仅是简简单单的介绍了如何生成 token,用户能够自定义一个拦截器,对 token 进行拦挡而后判断。对于每个用户的加密的算法,能够联合数据库,存储在数据库中这样每个人的加密算法就都不一样,不必放心一个 token 被破解所有的账户都会被破解。代码我曾经开源,欢送大家进行工具的补充和斧正,前期我会联合 SpringSecurity 进行整合。

正文完
 0