# 引言
# https
网络传输的安全性
必须有安全认证
# cookie
浏览器可以不用cookie
浏览器默认发送cookie
tomcat session活化技术,关闭后会把session序列化存储本地文件,启动时加载
# 简介
- 是跨语言的,原则上任何web都支持
- 适合分布式
- 可以做验证,支持加密算法
- 缺点是不能更新有效时间
# 数据结构
- 没有换行的
- 使用.分隔成3部分:标头Header、载荷payload、签名signature,base64编码,eg:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6IueuoeeQhuWRmCIsImV4cCI6MTY2NzQ0MjYxNSwidXNlcklkIjoiYWRtaW4ifQ.MaAgsYMWc05nMddmJrI1qmbvm5IXTV54hG7IKQJOvDw
Base64 编码/解码 | 菜鸟工具 (runoob.com) (opens new window)
# Header
{”alg”:“HS256”,“typ”:“JWT”}
# Payload
自定义
代码语言:javascript复制iss:
exp:
sub: 主题
aud:
nbf: 在此之前不可用
iat:
jti:
复制代码
不要再此存储敏感信息
实际上一般与redis联用
# signature
密钥不要改
# JWT的种类
typ属性
- nonsecure JWT:未经过签名,不安全的JWT
- JWS: 经过签名的jwt
公钥: 验证jwt是否合法(解密),是公开的(可能同时多人持有)。 私钥: 生成jwt使用(加密),通常个人保存私钥 公钥与私钥都能用于加密和解密,看实际用途
JWS,也就是WT Signature,其结构就是在之前nonsecure JWT的基础上,在头部声明签名算法,并在最后添加上签名。创建签名,是保证jwt不能被他人随意篡改。我们通常使用的WT一般都是WS为了完成签名,除了用到neaderf信息和payload信息外,还需要算法的密钥,也就是secretKey。加密的算法一般有2类: 对称加密:secretKey指加密密钥,可以生成签名与验签非对称加密:secretKey:指私钥,只用来生成签名,不能用来验签(验签用的是公钥) JWT的密钥或者密钥对,一般统一称为SON Web Key,也就是WK到目前为止,jw的签名算法有三种:
- HMAC【哈希消息验证码(对称)】:HS256/HS384/HS512
- RSASSA【RSA签名算法(非对称)】(RS256/RS384/RS512)
- ECDSA【椭圆曲线数据签名算法(非对称)】(ES256/ES384/ES512)
在线生成私钥公钥 https://www.ssleye.com/ssltool/pass_double.html (opens new window)
# 代码
# 依赖
推荐java-jwt
代码语言:javascript复制<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.19.2</version>
</dependency>
代码语言:javascript复制package com.zr;
import static org.junit.Assert.assertTrue;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.junit.Test;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
/**
* Unit test for simple App.
*/
public class AppTest
{
private String token="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6IueuoeeQhuWRmCIsImV4cCI6MTY2NzQ0MzUzOCwidXNlcklkIjoiYWRtaW4ifQ.83pbDb22U4EgfKWNeVLQh6AU4mBSTsNBva0eJqE1_WU";
public static void main(String[] args) {
AppTest appTest = new AppTest();
appTest.testJWT();
appTest.verifierToken();
}
@Test
public void testJWT() {
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.SECOND, 180);
//header部分,使用map,自动转json
Map<String, Object> header = new HashMap<>();
//加密算法,对称加密
header.put("alg", "HS256");
header.put("typ", "JWT");
String token = JWT.create()
.withHeader(header)
//载荷部分,自定义
.withClaim("userId","admin")
.withClaim("userName", "管理员")
//签名过期时间,180秒后过期
.withExpiresAt(calendar.getTime())
//签名加密算法
.sign(Algorithm.HMAC256("mima123456!"));
System.out.println(token);
this.token = token;
}
@Test
public void verifierToken(){
//获取校验对象
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("mima123456!")).build();
try{
//校验token
DecodedJWT decodedJWT= jwtVerifier.verify(this.token);
//校验通过获取载荷部分
Claim userId = decodedJWT.getClaim("userId");
Claim userName = decodedJWT.getClaim("userName");
System.out.println(userId.asString());
System.out.println(userName.asString());
System.out.println(decodedJWT.getExpiresAt());
}catch (TokenExpiredException e){
System.out.println("token过期: " e.getMessage());
}catch (SignatureVerificationException e){
System.out.println("token非法: " e.getMessage());
}catch (Exception e){
System.out.println(e.getMessage());
}
}
}
# 非对称加密
例如:rsa256算法
代码语言:javascript复制<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.9</version>
</dependency>
代码语言:javascript复制public static String getTokenRsa(Map<String,String> payload){
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE,7);
JWTCreator.Builder builder = JWT.create();
payload.forEach((k,v) -> builder.withClaim(k,v));
RSA rsa = new RSA(RSA_PRIVATE_KEY, null);
RSAPrivateKey privateKey= (RSAPrivateKey) rsa.getPrivateKey();
String token = builder.withExpiresAt(calendar.getTime()).sign(Algorithm.RSA256(null,privateKey));
return token;
}
public void decodeRsa(String token){
RSA rsa = new RSA(null, RSA_PUBLIC_KEY);
RSAPublicKey publicKey=(RSAPublicKey)rsa.getPublicKey();
JWTVerifier jwtVerifier = JWT.require(Algorithm.RSA256(publicKey,null)).build();
try{
//校验token
DecodedJWT decodedJWT= jwtVerifier.verify(token);
//校验通过获取载荷部分
Claim userId = decodedJWT.getClaim("userId");
Claim userName = decodedJWT.getClaim("userName");
System.out.println(userId.asString());
System.out.println(userName.asString());
System.out.println(decodedJWT.getExpiresAt());
}catch (TokenExpiredException e){
System.out.println("token过期: " e.getMessage());
}catch (SignatureVerificationException e){
System.out.println("token非法: " e.getMessage());
}catch (Exception e){
System.out.println(e.getMessage());
}
}