JWT生成用户Token使用笔记

Posted by Young Sheep on June 12, 2023

JWT

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).

JWT的组成

JWT由三部分组成:header.payload.signature

header头部

主要包括两部分信息:

  1. 声明类型(JWT)
  2. 声明加密算法,通常采用通常直接使用 HMAC SHA256

然后通过base64加密,很显然这是可以直接解密的。

payload载荷

存放有效信息的地方,例如账号信息等

signature签名信息

这个部分由 header 和 payload 经过 base64 编码然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。secret密钥是存储在服务器中的,可以用来生成token以及验证token是否正确。

JWT的应用

通过JWT绑定用户信息生成Token从而记录登录状态:

  • 用户进行登录时,将账号作为公开的信息存入payload中,根据服务器的secret密钥生成Token存储
  • 用户进行后续操作时必须在请求头中添加Token,然后服务器根据Token和服务器的secret密钥对signature签名信息进行验证,验证通过则放行。

Java代码实例

引入依赖

1
2
3
4
5
<dependency>
	<groupId>com.auth0</groupId>
	<artifactId>java-jwt</artifactId>
	<version>3.3.0</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
 * 生成签名
 * @param account 帐号
 * @return java.lang.String 返回加密的Token
 */
public static String sign(String account, String currentTimeMillis) {
	try {
		// 帐号加JWT私钥加密,encryptJWTKey为服务器设置的密钥
		String secret = account + Base64ConvertUtil.decode(encryptJWTKey);
		// 此处过期时间是以毫秒为单位,所以乘以1000
		Date date = new Date(System.currentTimeMillis() + Long.parseLong(accessTokenExpireTime) * 1000);
		Algorithm algorithm = Algorithm.HMAC256(secret);
		// 附带account帐号信息
		return JWT.create()
				.withClaim("account", account)	//设置payload载荷中的公开账号信息
				.withClaim("currentTimeMillis", currentTimeMillis)	//设置payload载荷中的时间信息,账号再次登录会生成新的Token,可通过Token创建时间与最新登录时间对比判断Token是否为最新的
				.withExpiresAt(date)  	//设置过期时间
				.sign(algorithm);		//设置加密算法
	} catch (UnsupportedEncodingException e) {
		logger.error("JWTToken加密出现UnsupportedEncodingException异常:{}", e.getMessage());
		throw new BusinessException(EmBusinessError.UNKNOWN_ERROR,"JWTToken加密出现UnsupportedEncodingException异常:" + e.getMessage());
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
 * 获得Token中payload载荷的公开信息
 * @param token 
 * @param claim payload载荷中公开信息的名称
 * @return java.lang.String Token中的公开信息
 */
public static String getClaim(String token, String claim) {
	try {
		DecodedJWT jwt = JWT.decode(token);
		// 只能输出String类型,如果是其他类型返回null
		return jwt.getClaim(claim).asString();
	} catch (JWTDecodeException e) {
		logger.error("解密Token中的公共信息出现JWTDecodeException异常:{}", e.getMessage());
		throw new BusinessException(EmBusinessError.UNKNOWN_ERROR,"解密Token中的公共信息出现JWTDecodeException异常:" + e.getMessage());
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
 * 校验token是否正确
 * @param token Token
 * @return boolean 是否正确
 */
public static boolean verify(String token) {
	try {
		// 帐号加JWT私钥解密,encryptJWTKey为服务器设置的密钥
		String secret = getClaim(token, Constant.ACCOUNT) + Base64ConvertUtil.decode(encryptJWTKey);
		Algorithm algorithm = Algorithm.HMAC256(secret);
		JWTVerifier verifier = JWT.require(algorithm).build();
		verifier.verify(token);
		return true;
	} catch (UnsupportedEncodingException e) {
		logger.error("JWTToken认证解密出现UnsupportedEncodingException异常:{}", e.getMessage());
		throw new BusinessException(EmBusinessError.UNKNOWN_ERROR,"JWTToken认证解密出现UnsupportedEncodingException异常:" + e.getMessage());
	} catch (JWTVerificationException e){
		logger.error("JWTToken认证解密出现JWTVerificationException异常:{}", e.getMessage());
		throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"JWTToken认证解密出现JWTVerificationException异常:" + e.getMessage());
	}
}