Token的组成规则
一个token分三部分,按顺序为:头部(header),载荷(payload),签证(signature) 由三部分生成token ,三部分之间用“.”号做分隔。
例如:“eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.MT8JrEvIB69bH5W9RUR2ap-H3e69fM7LEQCiZF-7FbI”。
- 头部:Jwt的头部承载两部分信息,声明类型(例如:typ=jwt)和 加密算法(例如 : alg=HS526)
- 载荷:载荷存放有效的信息,分为两种:① 标准中注册的声明的数据部分 ② 自定义数据部分。这两部分使用base64加密,然后存入到JWT的claim中 (使用withClaim(“key”:“value”))。
标准载荷:
iss: jwt签发者sub: jwt所面向的用户aud: 接收jwt的一方exp: jwt的过期时间,这个过期时间必须要大于签发时间nbf: 定义在什么时间之前,该jwt都是不可用的.iat: jwt的签发时间jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
自定义载荷:自定义载荷就是将自己需要的一些 key=>value数据放入到载荷中.
// 下面的 name=>zhangsan , role=>admin 就是自定义载荷数据
String token = JWT.create().withIssuer("auth0") // issuer 签发者.withExpiresAt(new Date(System.currentTimeMillis()+7200*1000)) // token过期时间 2H.withClaim("name","zhangsan") // 自定义存储的数据.withClaim("role","admin").sign(Algorithm.HMAC256("secret")); // token加签加密
- 签证(计算过程):HMACSHA256(base64UrlEncode(header) + “.” + base64UrlEncode(payload), signature) ,即需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加密钥secret组合加密,然后就构成了jwt的第三部分。
导入POM依赖
<dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>4.4.0</version></dependency>
生成token
我的这个例子就通过普通的maven项目来生成token,并不从web项目方面构建,但原理是一致的。
/*** 生成token* @return*/
public static String genToken(){try {Algorithm algorithm = Algorithm.HMAC256("secret"); // 使用HMAC256加密算法String token = JWT.create().withIssuer("auth0") // issuer 签发者.withIssuedAt(new Date(System.currentTimeMillis())).withExpiresAt(new Date(System.currentTimeMillis()+7200*1000)) // token过期时间 2H.withAudience("app") // 校验jwt的一方.withClaim("name","zhangsan") // 自定义存储的数据.withClaim("role","admin").sign(algorithm); // token加签加密return token;} catch (JWTCreationException exception){return "";}
}
在生成token的方法中,设置了issuer签发者,签发时间,token过期时间,校验token方,以及一些自定义数据载荷,签证加密算法使用 HMAC256。
① 签发时间必须小于过期时间
② 签发时间和过期时间都是使用秒来计算
③ 载荷都可以通过 withClaim 方法来添加,同时JWT也提供了标准载荷的方法,功能是一样的
验证token
/*** 校验token是否正确* @param token* @return*/
public static DecodedJWT verifyToken(String token){return JWT.require(Algorithm.HMAC256("secret")).build().verify(token);
}/*** 校验token,捕获异常并返回错误信息* @param token* @return*/
public static String checkToken(String token){try {verifyToken(token);return "token正确";}catch (SignatureVerificationException e){return "无效签名";}catch (TokenExpiredException e){return "token过期";}catch (AlgorithmMismatchException e){return "token算法不一致";}catch (Exception e){return "token无效";}
}
完整代码
package jwt_test;import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.*;
import com.auth0.jwt.interfaces.DecodedJWT;import java.util.Date;/*** 使用 java-jwt 生成token 以及 token 验证*/
public class JwtUtils {/*token: header(头部) + payload(载荷) + signature(签名)载荷就是存放有效信息的地方。基本上填2种类型数据-标准中注册的声明的数据-自定义数据(1) eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.(2) eyJpc3MiOiJhdXRoMCJ9.(3) MT8JrEvIB69bH5W9RUR2ap-H3e69fM7LEQCiZF-7FbI*//*** 生成token* @return*/public static String genToken(){try {Algorithm algorithm = Algorithm.HMAC256("secret"); // 使用HMAC256加密算法String token = JWT.create().withIssuer("auth0") // issuer 签发者.withIssuedAt(new Date(System.currentTimeMillis())).withExpiresAt(new Date(System.currentTimeMillis()+7200*1000)) // token过期时间 2H.withAudience("app") // 校验jwt的一方.withClaim("name","zhangsan") // 自定义存储的数据.withClaim("role","admin").sign(algorithm); // token加签加密return token;} catch (JWTCreationException exception){// Invalid Signing configuration / Couldn't convert Claims.return "";}}/*** 校验token,捕获异常并返回错误信息* @param token* @return*/public static String checkToken(String token){try {verifyToken(token);return "token正确";}catch (SignatureVerificationException e){return "无效签名";}catch (TokenExpiredException e){return "token过期";}catch (AlgorithmMismatchException e){return "token算法不一致";}catch (Exception e){return "token无效";}}/*** 校验token是否正确* @param token* @return*/public static DecodedJWT verifyToken(String token){return JWT.require(Algorithm.HMAC256("secret")).build().verify(token);}public static void main(String[] args) {String token = genToken();System.out.println(token);String res = checkToken(token);System.out.println(res);}
}
Token解析测试
https://config.net.cn/tools/Jwt.html
[说明]iss: jwt签发者. sub: jwt针对的用户aud: 校验jwt的一方exp: jwt的过期时间,过期时间需大于签发时间nbf: 定义在什么时间之前该jwt是不可用的.iat: jwt的签发时间jti: jwt的唯一身份标识,作一次性token,防重放攻击。