前言:本文主要简单介绍了什么是JWT和在JavaEE环境下如何使用JWT,简述JWT技术能够为Web开发带来什么样的帮助。
简介
JWT(JSON Web Token),可以生成一个加密的token,作为用户登录的令牌,当用户登录成功之后,发送给客户端。请求需要登录的资源或者接口的时候,将token携带,后端验证token是否合法。提供JSON形式作为Web应用中的令牌,用于在各发之间安全地将信息作为JSON对象传输。在数据传输过程中还可以完成数据加密、签名等处理。
作用
- 授权
最常见方案:JWT。一旦用户登录,每个后续请求将包含JWT,从而允许用户访问该令牌允许的路由、服务和资源。单点登录是当今广泛使用JWT的一项功能,因为开销很小并且可以在不同的域中轻松使用。 - 信息交换
JWT能在各方之间安全地传输信息,因为可以对JWT进行签名,所以可以确保发件人真实性。此外,由于签名是使用标头和有效负载计算的,因此还可以验证内容是否被篡改。
两种认证方式
基于传统的Session认证
基于JWT认证
JWT组成
-
Header
:标头,头部信息(固定),令牌类型和所使用的签名算法变量 作用 密钥 用于比对 算法 将Header和Payload加密成Signature { "alg": "HS256", "typ": "JWT" }
-
Playload
:有效载荷,存放信息(可以被解密,不安全),不能存放敏感信息变量 作用 签发人 Token令牌归属人 创建时间 令牌创建时间 失效时间 令牌失效时间 唯一标识 算法生成的唯一标识(jti -> sessionId) { "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }
-
Verify Signature
:签名,Header和Playload加上密钥加密而成,用于比对信息,防止篡改Header和Playload
JWT验证,主要验证 Verify Signature 部分是否合法
优势
- 简洁
数据量小,传输速度快 - 自包含
负载中包含了所有用户所需要的信息,避免了多次查询数据库
依赖包
jjwt
、java-jwt
<!-- jjwt -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- java-jwt -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.18.2</version>
</dependency>
使用JWT
引入依赖
java-jwt
是Java推荐使用的JWT实现库
<!-- java-jwt -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.18.2</version>
</dependency>
生成令牌 token
HashMap<String, Object> map = new HashMap<>(); // Header
// 设置过期时间 600s
Calendar instance = Calendar.getInstance();
instance.add(Calendar.SECOND, 600);
// 创建Token令牌
String token = JWT.create()
.withHeader(map) // Header
.withClaim("userId", 21) // Payload
.withClaim("username", "张三") // Payload
.withExpiresAt(instance.getTime()) // 指定令牌过期时间
.sign(Algorithm.HMAC256("!WENCLJNE")); // 签名
// 输出令牌
System.out.println("token = " + token);
// 输出结果:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MzIwMzQyNTgsInVzZXJJZCI6MjEsInVzZXJuYW1lIjoi5byg5LiJIn0.iaPw0l_7i0Ff96AzKd-RTm7S1p1WJYePbKF29n6hmJ0
验证令牌 token
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("!WENCLJNE")).build(); // 创建验证对象
DecodedJWT verify = jwtVerifier.verify(token); // 验证token
System.out.println(verify.getClaim("userId"));
System.out.println(verify.getClaim("username"));
System.out.println("过期时间:" + verify.getExpiresAt());
常见异常
SignatureVerificationException
:签名不一致AlgorithmMismatchException
:算法不匹配TokenExpiredException
:令牌过期InvalidClaimException
:失效的payload异常
封装工具类
JwtUtils.java
public class JWTUtils {
private static String TOKEN = "token!Q@W3e4r";
/**
* 生成token
* @param map //传入Payload
* @return 返回token
*/
public static String getToken(Map<String,String> map){
JWTCreator.Builder builder = JWT.create();
map.forEach((k,v)->{
builder.withClaim(k,v); // Payload 有效载荷
});
// 设置过期时间 7秒
Calendar instance = Calendar.getInstance();
instance.add(Calendar.SECOND,7);
builder.withExpiresAt(instance.getTime());
return builder.sign(Algorithm.HMAC256(TOKEN)); // 签名
}
/**
* 验证token
* @param token
* @return
*/
public static void verify(String token){
JWT.require(Algorithm.HMAC256(TOKEN)).build().verify(token); // 如果验证通过,则不会把报错,否则会报错
}
/**
* 获取token中payload
* @param token
* @return
*/
public static DecodedJWT getToken(String token){
return JWT.require(Algorithm.HMAC256(TOKEN)).build().verify(token);
}
}