JWT
JWT(Json Web Token),是一种广泛应用于网络环境传输、基于 JSON 的开放标准(RFC 7519),主要应用于单点登录(SSO)。
官方网址:https://jwt.io/
1.Maven坐标
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
2.JWT结构
举个例子:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MjAyODY1NTgsInVzZXJpZCI6MSwiZW1haWwiOiIxMjNAMTIzLmNvbSIsInVzZXJuYW1lIjoiQUNHa2FrYSJ9.UAXvhgPFVcibCWR5WY2CghNRE9aFiZ4Ps8kdFtxhW8k
官网解析结果:
JWT 主要包含三个部分:
Header 头部,包含了 Token类型 和 采用的加密算法,一般默认取如下值:
{
"alg": "HS256",
"typ": "JWT"
}
Payload 负载,包含三种声明Claim:
1)标准注册的声明,如下所示,建议但不强制使用;
iss
: jwt签发者
sub
: 面向的用户(jwt所面向的用户)
aud
: 接收jwt的一方
exp
: 过期时间戳(jwt的过期时间,这个过期时间必须要大于签发时间)
nbf
: 定义在什么时间之前,该jwt都是不可用的.
iat
: jwt的签发时间
jti
: jwt的唯一身份标识,主要用来作为一次性token
,从而回避重放攻击。
- 2)公共的声明;
- 3)私有的声明。
- Signature 签名,签名/签证。
3.加密算法
加密算法是单向函数散列算法,常见的有MD5、SHA、HAMC。
MD5(message-digest algorithm 5) (信息-摘要算法)缩写,广泛用于加密和解密技术,常用于文件校验。校验?不管文件多大,经过MD5后都能生成唯一的MD5值
SHA (Secure Hash Algorithm,安全散列算法) ,数字签名等密码学应用中重要的工具,安全性高于MD5
HMAC (Hash Message Authentication Code),散列消息鉴别码,基于密钥的Hash算法的认证协议。用公开函数和密钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。常用于接口签名验证。
4.代码结构
5.工具类
TokenUtil.java
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.demo.user.entity.User;
import org.apache.logging.log4j.util.Strings;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* <p> @Title TokenUtil
* <p> @Description Token 工具类
*
* @author DDKK.COM 弟弟快看,程序员编程资料站
* @date 2022/5/6 14:15
*/
public class TokenUtil {
public static final String JWT_SECRET_KEY = "testjwt";
/**
* 创建Token
*
* @param user 用户实体
* @return Token
*/
public static String createToken(User user) {
// 登录成功后生成JWT
// JWT的header部分,该map可以是空的,因为有默认值{"alg":HS256,"typ":"JWT"}
Map<String, Object> map = new HashMap<>();
// 30分钟过期时间
Calendar instance = Calendar.getInstance();
instance.add(Calendar.MINUTE,30);
return JWT.create()
// 添加头部
.withHeader(map)
// 添加payload
.withClaim("userid",user.getId())
.withClaim("username",user.getUsername())
.withClaim("email",user.getEmail())
// 设置过期时间
.withExpiresAt(instance.getTime())
// 设置签名 密钥
.sign(Algorithm.HMAC256(JWT_SECRET_KEY));
}
/**
* 检查Token是否有效
*
* @param token Token
* @return 是否有效
*/
public static boolean isValid(String token) {
if (Strings.isNotBlank(token)) {
try {
//创建验证对象,这里使用的加密算法和密钥必须与生成TOKEN时的相同否则无法验证
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(JWT_SECRET_KEY)).build();
//验证JWT
DecodedJWT decodedJwt = jwtVerifier.verify(token);
return new Date().before(decodedJwt.getExpiresAt());
} catch (Exception e) {
return false;
}
} else {
return false;
}
}
/**
* 检查Token所有Claims
*
* @param token Token
* @return Claims
*/
public static Map<String, Object> getClaims(String token) {
if (isValid(token)) {
//创建验证对象,这里使用的加密算法和密钥必须与生成TOKEN时的相同否则无法验证
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(JWT_SECRET_KEY)).build();
//验证JWT
DecodedJWT decodedJwt = jwtVerifier.verify(token);
//获取JWT中的数据,注意数据类型一定要与添加进去的数据类型一致,否则取不到数据
Map<String, Object> map = new HashMap<>();
map.put("userid", decodedJwt.getClaim("userid").asInt());
map.put("username", decodedJwt.getClaim("username").asString());
map.put("email", decodedJwt.getClaim("email").asString());
map.put("expire", decodedJwt.getExpiresAt());
return map;
} else {
throw new RuntimeException("Token验证失败,请重新登录");
}
}
}
6.测试
测试地址1: http://localhost:8081/index/login
请求方式:POST
响应结果:
测试地址2: http://localhost:8081/index/getInfo
请求方式:GET
响应结果: