jwt Token生成
JWT的原则是在服务器身份验证之后,将生成一个JSON对象并将其发送回用户
一、快速入门
-
搭建SpringBoot环境
-
pom.xml
中添加java-jwt
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency>
-
在
application.yml
中添加 token 设置
token:
# 令牌自定义标识
header: Authorization
# 令牌密钥
secret: 123
# 令牌有效期(默认30分钟)
expireTime: 30
- 实现Token服务类
@Component
@Service
public class ManufactoryTokenService{
// 令牌自定义标识
@Value("${token.header}")
private String header;
// 令牌秘钥
@Value("${token.secret}")
private String secret;
// 令牌有效期
@Value("${token.expireTime}")
private int expireTime;
protected static final long MILLIS_SECOND = 1000;
protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;
@Autowired
private RedisCache redisCache;
/**
* 创建令牌 ..不完整代码
* 创建token原理:随机生成一个不会重复的key;然后以键值对的方式将用户数据,存储到redis里边
* 之后我们将这个唯一的key加密生成token信息,我们从前端获取到token后解析成原本的key,
* 最后到redis里边就可以找到保存的登录用户数据了
* @param loginUser 用户信息
* @return 令牌
*/
public String createToken(User user){
String token = IdUtil.fastUUID();
user.setToken(token);
setUserAgent(user); // 设置数据;
refreshToken(user);
Map<String, Object> claims = new HashMap<>();
claims.put(Constants.LOGIN_USER_KEY, token);
return createToken(claims);
}
}
二、JWT 简介
1. JWT 秘钥组成
-
Header(头部) —— base64编码的Json字符串
- 声明类型,一般都是JWT
- 声明加密算法
{ 'typ': 'JWT', 'alg': 'HS256' }
-
Payload(载荷) —— base64编码的Json字符串
- 标准中注册的声明 (建议但不强制使用) :
- iss: jwt签发者
- sub: jwt所面向的用户
- aud: 接收jwt的一方
- exp: jwt的过期时间,这个过期时间必须要大于签发时间
- nbf: 定义在什么时间之前,该jwt都是不可用的.
- iat: jwt的签发时间
- jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
- 公共的声明可以添加任何的信息
-
Signature(签名)—— 使用指定算法,通过Header和Payload加盐计算的字符串
- header (base64后的)
- payload (base64后的)
- secret 秘钥
- 将这三个部分组合进行加密
eyJhbGciOiJIUzUxMiJ9.eyJjcnQiOjE1MjgzNDM4OTgyNjgsImV4cCI6MTUyODM0MzkxOCwidXNlcm5hbWUiOiJ0b20ifQ.E-0jxKxLICWgcFEwNwQ4pfhdMzchcHmsd8G_BTsWgkUmVwPzDd7jJlf94cAdtbwTLMm27ouYYzTTxMXq7W1jvQ
- 以点分开每个部分,base64编码组成的是可以反编译回去的
2. 生成Token
private String createToken(Map<String, Object> claims){
JwtBuilder token = Jwts.builder();
token.setClaims(claims);
String compact = token.signWith(SignatureAlgorithm.HS512, secret).compact();
return compact;
}
- 生成token 我们一般用
Jwts.builder()
创建一个 JwtBuilder 对象; - JwtBuilder 里边常用属性
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private Header header; //头部
private Claims claims; //声明
private String payload; //载荷
private SignatureAlgorithm algorithm; //签名算法
private Key key; //签名key
private byte[] keyBytes; //签名key的字节数组
private CompressionCodec compressionCodec; //压缩算法
3. 解析Token
private static Claims getClaimsFromToken(String token) {
Claims claims;
try {
claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
claims = null;
}
return claims;
}
- 通过 Jwts.parser() 返回的是一个
JwtParser
对象;即DefaultJwtParser
对象
private static final String ISO_8601_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
private static final int MILLISECONDS_PER_SECOND = 1000;
private ObjectMapper objectMapper = new ObjectMapper();
private byte[] keyBytes; //签名key字节数组
private Key key; //签名key
private SigningKeyResolver signingKeyResolver; //签名Key解析器
private CompressionCodecResolver compressionCodecResolver = new DefaultCompressionCodecResolver(); //压缩解析器
Claims expectedClaims = new DefaultClaims(); //期望Claims
private Clock clock = DefaultClock.INSTANCE; //时间工具实例
private long allowedClockSkewMillis = 0; //允许的时间偏移量