2025年JWT使用教程

JWT使用教程一 什么是 JW JWT 是一种用于双方之间传递安全信息的简洁的 URL 安全的表述性声明规范 JWT 作为一个开放的标准 定义了一种简洁的 自包含的方法用于通信双方之间以 Json 对象的形式安全的传递信息 因为数字签名的存在 这些信息是可信的 JWT 可以使用 HMAC 算法或者是 RSA 的公私秘钥对进行签名 简洁

大家好,我是讯享网,很高兴认识大家。

一,什么是 JW

JWT是一种用于双方之间传递安全信息的简洁的、URL安全的表述性声明规范。JWT作为一个开放的标准,定义了一种简洁的,自包含的方法用于通信双方之间以Json对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。

  • 简洁: 可以通过URL,POST参数或者在HTTP header发送,因为数据量小,传输速度也很快
  • 自包含:负载中包含了所有用户所需要的信息,避免了多次查询数据库

二,JWT 组成部分

2.1,令牌组成

  • 标头:Header
  • 有效载荷:Payload
  • 签名:Singature

2.2,详细

标头
一个json字符串,包含当前令牌名称,以及加密算法,

{ 
   "typ":"JWT","alg":"HS256"} 

讯享网

typ用来标识整个token是一个jwt字符串,alg代表签名和摘要算法,一般签发JWT的时候,只要typ和alg就够了,生成方式是将header部分的json字符串经过Base64Url编码;
载荷
存放有效的信息,可以是标准声明,也可以是自定义的内容,可以在代码中获取;

  • 标准声明
讯享网iss: jwt签发者 sub: jwt所面向的用户 aud: 接收jwt的一方 exp: jwt的过期时间,这个过期时间必须要大于签发时间 nbf: 定义在什么时间之前,该jwt都是不可用的. iat: jwt的签发时间 jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。 

签名
由头部信息使用base64加密之后,拼接上载荷使用base64加密之后的部分,在加上当前的密钥,进行头部中的加密算法进行加密

这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。

三,在Java中使用

在Java中使用JWT,有许多的第三方库,如:java-jwt,jjwt等;本文主要介绍这两种库;

3.1,java-jwt

官网:https://github.com/auth0/java-jwt
1,导入依赖

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

2,代码实现

  • 生成JWT
讯享网void sign() { 
    // 创建签名算法 Algorithm algorithm = Algorithm.HMAC256("esyrg"); // 标头 Map<String, Object> headMap = new HashMap<>(); headMap.put("type", "JWT"); headMap.put("alg", "HMAC256"); JWTCreator.Builder builder = JWT.create().withHeader(headMap); // 载荷 JWTCreator.Builder builder1 = builder.withClaim("iss", "esyrg") .withClaim("sub", "user"); // 过期时间,2分钟 // 这里设置过期时间不能用Calendar生成Date,否则设置的过期时间无效 long l = System.currentTimeMillis() + (1000 * 60 * 2); Date date = new Date(l); String jwt = builder1.withExpiresAt(date).sign(algorithm); System.out.println(jwt); } 

注意:设置过期时间不能用Calendar生成Date,否则设置的过期时间无效,至于原因本人也不清楚。


讯享网

  • 验证
void verifyJwt() { 
    String jwt = "eyJ0eXAiOiJKV1QiLCJ0eXBlIjoiSldUIiwiYWxnIjoiSFMyNTYifQ.eyJzdWIiOiJ1c2VyIiwiaXNzIjoiZXN5cmciLCJleHAiOjE2NjE1MjM5NTh9.FMl14s3GJ5n9sKrpMIYIqgSAQ-isWTTSdT6InUli1lQ"; Algorithm algorithm = Algorithm.HMAC256("esyrg"); DecodedJWT verify = JWT.require(algorithm).build().verify(jwt); // 获取标头 String header = verify.getHeader(); // 获取载荷或自定义信息 Claim iss = verify.getClaim("iss"); String string = iss.asString(); } 

常用方法:

  • decodeJwt(String token)
  • decode(String token)

以上这两种方法都可以解析获取jwt中的信息,但是这两种方法不会验证jwt的签名。

讯享网void verifyJwt() { 
    String jwt = "eyJ0eXAiOiJKV1QiLCJ0eXBlIjoiSldUIiwiYWxnIjoiSFMyNTYifQ.eyJzdWIiOiJ1c2VyIiwiaXNzIjoiZXN5cmcifQ.zLlDZzys7xEbMD6bwSEdTuscS5LGYEDCAyxlUj5AWx8"; DecodedJWT decode = JWT.decode(jwt); Claim iss = decode.getClaim("iss"); } 

常见异常

令牌过期异常:TokenExpiredException
签名无效或key错误异常:SignatureVerificationException
算法不匹配异常:AlgorithmMismatchException

可用签名算法(摘自官网)

JWS 算法 描述
HS256 HMAC256 带有 SHA-256 的 HMAC
HS384 HMAC384 带有 SHA-384 的 HMAC
HS512 HMAC512 带有 SHA-512 的 HMAC
RS256 RSA256 带有 SHA-256 的 RSASSA-PKCS1-v1_5
RS384 RSA384 带有 SHA-384 的 RSASSA-PKCS1-v1_5
RS512 RSA512 带有 SHA-512 的 RSASSA-PKCS1-v1_5
ES256 ECDSA256 曲线 P-256 和 SHA-256 的 ECDSA
ES384 ECDSA384 具有曲线 P-384 和 SHA-384 的 ECDSA
ES512 ECDSA512 曲线 P-521 和 SHA-512 的 ECDSA

3.2,jjwt

官网:https://github.com/jwtk/jjwt
导入依赖

<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.5</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.5</version> <scope>runtime</scope> </dependency> 

代码实现

  • 生成JWT
讯享网void contextLoads() { 
    // 标头 Map<String, Object> headMap = new HashMap<>(); headMap.put("type", "JWT"); headMap.put("alg", "HS256"); // 自定义信息 Map<String, Object> cliMap = new HashMap<>(); cliMap.put("id", "1"); cliMap.put("name", "ren"); // 过期时间 long l = System.currentTimeMillis() + (1000 * 60 * 2); Date date = new Date(l); JwtBuilder jwtBuilder = Jwts.builder().setHeader(headMap) .setClaims(cliMap) .setExpiration(date); // 签名,这里有两种方法 // 第一种,此方法要求key长度必须足够长,否则会报错 // SecretKey secretKey = Keys.hmacShaKeyFor("esyrgfdfdfdf".getBytes()); // String jwt = jwtBuilder.signWith(secretKey,SignatureAlgorithm.HS256).compact(); // 第二种,建议采用此法方法 // SecretKey secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256); String jwt = jwtBuilder.signWith(secretKey).compact(); System.out.println(jwt); } 
  • 解析JWT
void verifyJwt() { 
    String jwt = "eyJ0eXBlIjoiSldUIiwiYWxnIjoiSFMyNTYifQ.eyJuYW1lIjoicmVuIiwiaWQiOiIxIn0.6LxD4SdCPVYbbijePBGQu2oIRTa23ZsI-wHMzhYfIx8"; // 这里的secretKey必须和生成时用的secretKey一样 Jwt parse = Jwts.parserBuilder().setSigningKey(secretKey).build().parse(jwt); Claims body = (Claims) parse.getBody(); Object name = body.get("name"); Header header = parse.getHeader(); Object type = header.get("type"); // 还可以以下面这种方式解析jwt // Jws<Claims> claimsJws = Jwts.parserBuilder().setSigningKey(secretKey).build().parseClaimsJws(jwt); // Claims body = claimsJws.getBody(); // JwsHeader header = claimsJws.getHeader(); } 

常见异常

四,JWT工具类

以下为JWT工具类,使用的依赖是java-jwt。

讯享网/ * JWT工具类 * <p> * 使用的是java-jwt * * @Author: Esyrg * @Date: 2022/8/27 17:57 */ public class JWTUtils { 
    / * 生成签名 * * @param claims 附带信息 * @param secret 生成token的密钥 * @param expireTime 过期时间,单位:秒 * @return 加密的token */ public static String sign(Map<String, String> claims, String secret, Long expireTime) { 
    Date date = new Date(System.currentTimeMillis() + expireTime * 1000); Algorithm algorithm = Algorithm.HMAC256(secret); // 附带信息 JWTCreator.Builder builder = JWT.create(); for (String key : claims.keySet()) { 
    builder.withClaim(key, claims.get(key)); } // 过期时间 builder.withExpiresAt(date); return builder.sign(algorithm); } / * 验证token * * @param token 要验证的token * @param secret 密钥 * @return 是否正确 */ public static boolean verify(String token, String secret) { 
    Algorithm algorithm = Algorithm.HMAC256(secret); JWTVerifier build = JWT.require(algorithm).build(); build.verify(token); return true; } / * 验证token * * @param token 要验证的token * @param secret 密钥 * @return 状态及信息,1:正确,0:错误 */ public static Map<String, Object> verifyInfo(String token, String secret) { 
    Map<String, Object> map = new HashMap<>(); try { 
    Algorithm algorithm = Algorithm.HMAC256(secret); JWTVerifier build = JWT.require(algorithm).build(); build.verify(token); map.put("state", "1"); map.put("message", "令牌正确"); return map; } catch (TokenExpiredException e) { 
    // 需要打印时,可以去掉注释 // e.printStackTrace(); map.put("state", "0"); map.put("message", "令牌过期"); return map; } catch (SignatureVerificationException e) { 
    // e.printStackTrace(); map.put("state", "0"); map.put("message", "验证错误"); return map; } catch (AlgorithmMismatchException e) { 
    // e.printStackTrace(); map.put("state", "0"); map.put("message", "算法不匹配"); return map; } catch (Exception e) { 
    // e.printStackTrace(); map.put("state", "0"); map.put("message", e.getMessage()); return map; } } / * 获取token中的信息,无需解密也能获得 * * @param token 要解析的token * @param key 信息的key * @return 信息 */ public static String getClaims(String token, String key) { 
    try { 
    DecodedJWT decode = JWT.decode(token); return decode.getClaim(key).asString(); } catch (JWTDecodeException e) { 
    return null; } } / * 获取过期时间,无需解密也能获得 * * @param token 需要解析的token * @return 过期时间 */ public static Date getExpiresAt(String token) { 
    try { 
    DecodedJWT decode = JWT.decode(token); return decode.getExpiresAt(); } catch (JWTDecodeException e) { 
    return null; } } / * 获取token的剩余时间,无需解密也能获得,单位:毫秒 * * @param token 需要解析的token * @return 剩余时间,如果已过期,则返回 -1 */ public static Long getExpiresAtMill(String token) { 
    try { 
    DecodedJWT decode = JWT.decode(token); long l = decode.getExpiresAt().getTime() - System.currentTimeMillis(); return l < 0 ? -1L : l; } catch (JWTDecodeException e) { 
    return null; } } } 
小讯
上一篇 2025-01-25 18:40
下一篇 2025-02-14 15:22

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/34233.html