Spring Jwt 生成 Token
由来
当前后端结合的时候可以根据请求返回数据,在服务端储存 cookie,session 等,但当前后端分离后,不光后端无法渲染前端,还会收到许多前端传来的请求,这时就需要 token 来验证用户信息。
Token
Token 是在服务端产生的。如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回 Token 给前端。前端可以在每次请求的时候带上 Token 证明自己的合法地位。如果这个 Token 在服务端持久化(比如存入数据库),那它就是一个永久的身份令牌。
为防止密码等信息的泄露,常常是前端只传递 Token 除登陆等少量操作不会传递有关用户信息的内容,而 Token 也可以时常更新,以保证安全性。
JWT
在 java 中 JWT 便是生成 Token 的非常方便的工具。
可以用来验证用户身份以及对路由,服务和资源的访问权限进行验证。
结构
JWT是由三段信息构成的,例如:
eyJhbGciOiJIUzI1NiJ9.
eyJqdGkiOiJjOTRmMTYyNy00MzMxLTQzZmMtYWY4My1iNmM5ZTA1M2UzNTIiLCJpYXQiOjE1NjcwODQ1MzUsInN1YiI6InN5c3RlbSIsImlzcyI6Im5weSIsInVzZXJJZCI6MTM4OSwidXNlcm5hbWUiOiIxMSIsImV4cCI6MTU2NzE5MjUzNX0.
hUssKQEWZwg59tCls7FseXtvkde6XQ44FVSM1R437Rw
Header
JWT的头部承载两部分信息:token类型和采用的加密算法。
{
“alg”: “HS256”,
“typ”: “JWT”
}
声明加密的算法:有许多种,选择自己想要的就好,一般编程软件会有提示
Payload
载荷就是存放有效信息的地方。
有效信息包含三个部分
- 标准中注册的声明
- 公共的声明
- 私有的声明
标准中注册的声明 (建议但不强制使用) :
iss: JWT 签发者
sub: 面向的用户(JWT 所面向的用户)
aud: 接收 JWT 的一方
exp: 过期时间戳(jwt的过期时间,这个过期时间必须要大于签发时间)
nbf: 定义在什么时间之前,该 JWT 都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性 Token,从而回避重放攻击。
secret
这个部分需要 base64 加密后的 header 和 base64 加密后的 payload 使用。连接组成的字符串,然后通过 header 中声明的加密方式进行加盐值 secret 组合加密,然后就构成了 JWT 的第三部分。
密钥secret是保存在服务端的,服务端会根据这个密钥进行生成token和进行验证,所以需要保护好。
依赖注入
如今常见的依赖有两种(本文以第二种为例):
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
代码实现
User类自己实现就好,简单的面向对象。
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class JwtUtil {
/**
* 获取token
* @param encryKey
* @param minutes
* @return
*/
public static String getToken(User user, String encryKey, long minutes){
long currentTime = System.currentTimeMillis();
//也可以直接传入 Map<String, Object> 做简单的修改即可
Map<String, Object> map = new HashMap<>();
map.put("userId", user.getId());
return Jwts.builder()
.setId(UUID.randomUUID().toString()) //当前用户
.setIssuedAt(new Date()) //签发日期
.setSubject("system") //说明
.setIssuer("npy") //签发者信息
.signWith(SignatureAlgorithm.HS256, encryKey) //加密方式
.addClaims(map)
.setExpiration(new Date(currentTime + minutes * 1000 * 60)) //过期时间
.compact();
}
/**
* 验证是否到时间
* @param token
* @param encryKey
* @return
*/
public static boolean isExpiration(String token, String encryKey){
try {
long currentTime = System.currentTimeMillis();
if (Jwts.parser().setSigningKey(encryKey).parseClaimsJws(token).getBody().getExpiration().after(new Date(currentTime))){
return true;
}else {
return false;
}
}catch (Exception e){
return false;
}
}
/**
* 获取claims
* @param token
* @param encryKey
* @return
*/
public static Claims getClamis(String token, String encryKey){
try {
Claims claims = Jwts.parser().setSigningKey(encryKey).parseClaimsJws(token).getBody();
return claims;
}catch (Exception e){
return null;
}
}
// public static void main(String[] args) {
// String token =
//"eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJjOTRmMTYyNy00MzMxLTQzZmMtYWY4My1iNmM5ZTA1M2UzNTIiLCJpYXQiOjE1NjcwODQ1MzUsInN1YiI6InN5c3RlbSIsImlzcyI6Im5weSIsInVzZXJJZCI6MTM4OSwidXNlcm5hbWUiOiIxMSIsImV4cCI6MTU2NzE5MjUzNX0.hUssKQEWZwg59tCls7FseXtvkde6XQ44FVSM1R437Rw";
// System.out.println(JwtUtil.getClamis(token, "salt").get("userId"));
// System.out.println(JwtUtil.getClamis(token, "salt").get("username"));
// }
}