JWT 官网:https://jwt.io/introduction/ JWT 在线校验:https://jwt.io/#debugger-io 推荐的测试代码:#Test
JSON WEB TOKEN,它定义了一种紧凑且自包含的方式,用于将信息作为 JSON 对象安全地在各方之间传输信息。此信息可以验证和信任,因为它是数字签名。JWT 可以使用密钥(使用HMAC算法)或使用 RSA 或 ECDSA 进行公钥/私钥对进行签名。
我们一般只去API使用 授权、校验
标头通常由两部分组成:令牌的类型(即 JWT)和正在使用的签名算法,如 HMAC SHA256 或 RSA。
例如:
{
"alg": "HS256",
"typ": "JWT"
}
然后,此 JSON编码为 Base64Url,以形成 JWT 的第一部分。
令牌的第二部分是有效负载,其中包含声明。声明是关于实体(通常为用户)和其他数据的语句。有三种类型的索赔:已登记、公共和私人索赔。
示例有效负载可能是:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
然后对有效负载进行 Base64Url编码,以形成 JSON Web 令牌的第二部分。
请注意,对于已签名的令牌,此信息虽然可防止篡改,但任何人都可以阅读。除非对 JWT 进行加密,否则不要将机密信息放在 JWT 的有效负载或标头元素中。
要创建签名部分,您必须使用编码标头、编码有效负载、机密、标头中指定的算法,并签名。
例如,如果要使用 HMAC SHA256 算法,将采用以下方式创建签名:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
签名用于验证邮件未随之更改,对于使用私钥签名的令牌,它还可以验证 JWT 的发件人是否为它所说的发件人。
输出是三个 Base64-URL 字符串,由点分隔,这些点可以在 HTML 和 HTTP 环境中轻松传递,但与基于 XML 的标准(如 SAML)相比,更紧凑。
下面显示了一个 JWT,它具有以前的标头和有效负载编码,并且它使用机密进行签名。
如果要使用 JWT 并付诸实践,可以使用 jwt.io器解码、验证和生成 JWT。
导包
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.13.0</version>
</dependency>
调用 JWT.create() 方后面的链式调用,添加相关参数
// 生成Token
@Test
public void createJwt(){
HashMap<String,Object> hashMap = new HashMap<>();
Calendar instance = Calendar.getInstance();
instance.add(Calendar.SECOND,100); // 设置超时时间 100s
String token = JWT.create()
.withHeader(hashMap) // Header
.withClaim("username", "张三") // Payload
.withClaim("age", 20) // Payload
.withExpiresAt(instance.getTime()) // 设置超时时间
.sign(Algorithm.HMAC256("!Govbuy2021JWT~ZLK")); // 自己生成的签名,足够复杂就行,不要泄露就行
System.out.println("Token is in next line:");
System.out.println(token);
}
结果 如图
额外知识:
如果 相同的负载 字段名,例如 “username” 一个叫张三 、一个叫李四,那么就会默认使用代码顺序下面的”username”,即Claims 中 只会存在一个 “username”
调用 JWT 验证对象 JWTVerifier 的 verify() 方法 解析
@Test
public void ValidateJwt(){
JWTVerifier build = JWT.require(Algorithm.HMAC256("!Govbuy2021JWT~ZLK")).build();
DecodedJWT verify = build.verify("" +
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MTM2MTM3MjksImFnZSI6MjAsInVzZXJuYW1lIjoi5byg5LiJIn0.G2tQ5564EDx1V7yF4GT6tTCn5lLZHSSdOfpm3ae73w4");
// 获取令牌内 包含的信息
String username = verify.getClaim("username").asString();
int age = verify.getClaim("age").asInt();
System.out.println(username);
System.out.println(age);
}
如果令牌 超过设置的过期时间 ,就会报 令牌超时异常
com.auth0.jwt.exceptions.TokenExpiredException: The Token has expired on Thu Feb 18 09:38:12 CST 2021.
创建 自己的工具类
import cn.hutool.core.date.DateUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
/**
* @author : zanglikun
* @date : 2021/2/18 9:58
* @Version: 1.0
* @Desc : JWT生成工具。具体JWT文章请访问:
*/
public class JWTUtils {
// 定义的加密密钥
private static final String MYSign = "!HEFEI2021JWT~ZLK";
/**
* 生成 令牌
* @param map 你创建的参数集合
* @return
*/
public static String getToken(Map<String, String> map) {
Calendar instance = Calendar.getInstance();
instance.add(Calendar.DATE,7); // 设置超时时间 7 天
System.out.println(instance.getTime());
// 创建 JWT Builder
JWTCreator.Builder builder = JWT.create();
// 设置 Payload
map.forEach((k, v) -> {
builder.withClaim(k, v);
});
// 超时时间 与 Sign
String sign = builder.withExpiresAt(instance.getTime())
.sign(Algorithm.HMAC256(MYSign));
return sign;
}
/**
* 验证 Token 的合法性 只要不抛异常,就算令牌 验证成功
* @param token 你传递的token
*/
public static void verifyToken(String token) {
JWTVerifier build = JWT.require(Algorithm.HMAC256(MYSign)).build();
DecodedJWT verify = build.verify(token);
//System.out.println("签名验证成功,会打印此话");
}
/**
* 获取 Token中 信息,以后 直接 通过 DecodedJWT 进行 .getClaim.as数据类型() 获取;
* @param token 你传递的token
* @return DecodedJWT 可用于获取数据
*/
public static DecodedJWT getInfo(String token) {
return JWT.require(Algorithm.HMAC256(MYSign)).build().verify(token);
}
public static void main(String[] args) {
HashMap hashMap = new HashMap();
hashMap.put("Abc你好123","Abc你好123");
String token = JWTUtils.getToken(hashMap);
/* JWT 常用方法
JWTUtils.getInfo(token).getHeader();
JWTUtils.getInfo(token).getPayload();
JWTUtils.getInfo(token).getSignature();
*/
System.out.println(JWTUtils.getInfo(token).getClaims());
Long exp = JWTUtils.getInfo(token).getClaim("exp").asLong();
//这里使用了Hutool的工具 打印时间
System.out.println("过期时间是:" + DateUtil.date(exp*1000));
}
}
未来在单体架构,就放在 拦截器 放行登录接口就行,减少验签等代码的冗余,分布式架构,就放在网关里面即可。
<!--Hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.15</version>
</dependency>
// 创建JWT
@Test
public void JWT() {
Map payload = new HashMap<>();
payload.put("账号","123");
payload.put("姓名","汪顺");
// Token 有效期是15天 可不设置
payload.put("expire_time",System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 15);
// 生成Token并执行加密方式:hs256 密码是123456
String token = JWTUtil.createToken(payload, JWTSignerUtil.hs256("123456".getBytes()));
System.out.println(token);
}
// 验证JWT
@Test
public void UnJWT() {
// 这是我们生成的Token
String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyLotKblj7ciOiIxMjMiLCLlp5PlkI0iOiLmsarpoboiLCJleHBpcmVfdGltZSI6MTYzNzU4MTIyMzQ4NH0.SWZd0KmcNkrRyDn9uTp1O3CkFaiCmSXlrf3Gyw-GYck";
try {
// 这是验证Token完整性 如果有异常,就说明Token不完整
JWTValidator.of(token).validateAlgorithm(JWTSignerUtil.hs256("123456".getBytes()));
// 判断Token是否超时
JWTPayload payload = JWTUtil.parseToken(token).getPayload();
Long nowtime = new Date().getTime();
if (Long.valueOf((Long) payload.getClaim("expire_time")) < nowtime){
System.out.println("Token超时");
int i = 1/0;
}
// 打印负载的内容
System.out.println(payload.getClaim("账号"));
System.out.println(payload.getClaim("姓名"));
System.out.println(DateUtil.date((Long) payload.getClaim("expire_time")));
}catch (Exception e){
System.out.println("Token校验不通过");
}
}
特殊说明: 解决问题的光鲜,藏着磕Bug的痛苦。 万物皆入轮回,谁也躲不掉! 以上文章,均是我实际操作,写出来的笔记资料,不会出现全文盗用别人文章!烦请各位,请勿直接盗用!