目录
- 前置内容
- 令牌
- jwt
- cookie,token,session的区别与关系
- cookie
- session
- token
- 使用
- 关键内部类
- Claims
- Jwts
- SignatureAlgorithm
前置内容
令牌
描述:
- 令牌是一种用于身份验证和授权的机制,它通常是一个字符串。
- 由服务器生成,并颁发给客户端,客户端可以在后续的请求中使用该令牌来访问受保护的资源。
令牌要求
- 时效性:令牌具有有效期
- 安全性:令牌应难以伪造或篡改,应当加密或签名
- 便携性:令牌可以轻松地通过HTTP请求头、查询参数或请求体进行传输。
jwt
描述:
全名:JSON Web Token,一种JSON格式的网络令牌
结构
一段JWT令牌分为如下三部分
- 头部:令牌类型(JWT)+算法签名(如HS256、RS256)
- 有效载荷:JWT的主体内容,包含用户身份信息、权限和角色信息和其他的业务数据(这类数据不属于认证的业务)
- 签名:对头部和有效载荷的编码结果进行签名得到的字符串,用于验证JWT的完整性和真实性。
说明
不建议存放私密信息,因为JWT令牌不具备加密的功能
cookie,token,session的区别与关系
参考B站视频
cookie
客户端向服务器发送http请求后,其中携带部分常用内容,如登录状态等其他非关键但常用信息
过去曾存储过账号密码等重要内容,每次客户端访问浏览器时会携带这些数据,但不安全因此引出session
session
客户端向服务器发出请求后,服务器进行认证,通过后,生成并存储如下内容
- SessionID:一串无序的字符串,记录用户的会话
- 会话时间:每个会话都具备有效期,超过此有效期,则会话失效,此时需要重新认证
并将这些内容传递给客户端(传递方式包括但不限于cookie、响应头等)
客户端每次访问服务器时带上这些数据(主要是SessionID)
服务器端接收到SessionID后,会进行相应匹配认证机制
token
JWT是token中的一种
出于服务器性能、安全方面的考虑,出现token
客户端登录后,服务器进行认证,生成JWT返回给客户端
客户端每次访问服务器时,带上JWT即可
使用
jwt原理如上,但在使用时,将其当作一个工具包即可
关键内部类
Claims
描述:存储和传输关于实体(如用户)的身份验证和授权信息。
示例1
手动生成Clamis,编写相关信息,并写入到JWT中
package com.nxin.framework.service.auth;import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.SignatureAlgorithm;
import org.junit.jupiter.api.Test;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;import java.util.Date;
import java.util.HashMap;
import java.util.Map;public class test {@Testpublic void test01() {String secretKey = "mySecretKey";Map<String, Object> claims = new HashMap<>();claims.put("role", "admin"); // 用户的角色claims.put("permissions", new String[]{"read", "write", "delete"}); // 用户的权限列表String jwt = Jwts.builder().setClaims(claims).setSubject("1234567890") // 设置主题声明,通常用作用户ID.setIssuedAt(new Date()) // 设置签发时间.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000)) // 设置过期时间.signWith(SignatureAlgorithm.HS256, secretKey) // 使用HS256算法和密钥签名.compact(); // 生成JWT字符串;System.out.println(jwt);}
}
示例2
解析JWT,获取Clamis对象,以及其他相关信息
@Testpublic void test3() {String secretKey = "mySecretKey";String jwt = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwicm9sZSI6ImFkbWluIiwicGVybWlzc2lvbnMiOlsicmVhZCIsIndyaXRlIiwiZGVsZXRlIl0sImV4cCI6MTczNDEzODc2MCwiaWF0IjoxNzM0MTM1MTYwfQ.EWDHOGGLmy6gYUh7gpf1i2ekhZKA10DtWL_3u08-NWM";try {// 解析JWTClaims claims = Jwts.parser().setSigningKey(secretKey) // 设置签名密钥.parseClaimsJws(jwt) // 解析JWT.getBody(); // 获取Claims对象// 打印claims内容(可选)System.out.println(claims);// 提取声明String role = claims.get("role", String.class);Object permissionsObj = claims.get("permissions");if (permissionsObj instanceof List) {List<String> permissions = (List<String>) permissionsObj;for (String permission : permissions) {System.out.println(permission);}} else {System.out.println("Permissions field is not a List<String>");}} catch (SignatureException e) {System.err.println("JWT signature does not match: " + e.getMessage());} catch (Exception e) {System.err.println("An error occurred: " + e.getMessage());}}
Jwts
描述:供了创建和解析JWT的静态方法,用于生成JWT令牌和解析JWT令牌的核心类。
示例1
jwt的构建
方法汇总
方法名 | 描述 |
---|---|
setHeader(Header header) | 设置(并替换)任何现有的头部为指定的头部 |
setHeader(Map<String, Object> header) | 设置(并替换)任何现有的头部为指定的Map头部 |
setHeaderParams(Map<String, Object> params) | 将指定的名/值对应用到头部,如果头部不存在则创建 |
setHeaderParam(String name, Object value) | 将指定的名/值对应用到头部,如果头部不存在则创建 |
setPayload(String payload) | 设置JWT的负载为明文(非JSON)字符串 |
setClaims(Claims claims) | 设置JWT的负载为JSON Claims实例 |
setClaims(Map<String, Object> claims) | 设置JWT的负载为JSON Claims实例,由Map填充 |
addClaims(Map<String, Object> claims) | 将所有给定的名/值对添加到JSON Claims负载中 |
setIssuer(String iss) | 设置JWT Claims的iss (发行者)值 |
setSubject(String sub) | 设置JWT Claims的sub (主题)值 |
setAudience(String aud) | 设置JWT Claims的aud (受众)值 |
setExpiration(Date exp) | 设置JWT Claims的exp (过期时间)值 |
setNotBefore(Date nbf) | 设置JWT Claims的nbf (生效时间)值 |
setIssuedAt(Date iat) | 设置JWT Claims的iat (签发时间)值 |
setId(String jti) | 设置JWT Claims的jti (JWT ID)值 |
claim(String name, Object value) | 设置自定义JWT Claims参数值 |
signWith(SignatureAlgorithm alg, byte[] secretKey) | 使用指定的算法和密钥对构造的JWT进行签名 |
signWith(SignatureAlgorithm alg, String base64EncodedSecretKey) | 使用指定的算法和BASE64编码的密钥对JWT进行签名 |
signWith(SignatureAlgorithm alg, Key key) | 使用指定的算法和密钥对构造的JWT进行签名 |
compressWith(CompressionCodec codec) | 使用指定的压缩编解码器对JWT体进行压缩 |
compact() | 构建JWT并将其序列化为紧凑的、URL安全的字符串 |
public void test01() {String secretKey = "mySecretKey";Map<String, Object> claims = new HashMap<>();claims.put("role", "admin"); // 用户的角色claims.put("permissions", new String[]{"read", "write", "delete"}); // 用户的权限列表String jwt = Jwts.builder().setClaims(claims).setSubject("1234567890") // 设置主题声明,通常用作用户ID.setIssuedAt(new Date()) // 设置签发时间.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000)) // 设置过期时间.signWith(SignatureAlgorithm.HS256, secretKey) // 使用HS256算法和密钥签名.compact(); // 生成JWT字符串;System.out.println(jwt);jwt_all=jwt;}
示例2
jwt解析,获取jwt内部的相关信息
方法说明
方法名 | 描述 |
---|---|
requireId(String id) | 确保解析的JWT中包含指定的jti (JWT ID)。如果缺失或解析的值与指定值不匹配,将抛出异常。 |
requireSubject(String subject) | 确保解析的JWT中包含指定的sub (主题)。如果缺失或解析的值与指定值不匹配,将抛出异常。 |
requireAudience(String audience) | 确保解析的JWT中包含指定的aud (受众)。如果缺失或解析的值与指定值不匹配,将抛出异常。 |
requireIssuer(String issuer) | 确保解析的JWT中包含指定的iss (发行者)。如果缺失或解析的值与指定值不匹配,将抛出异常。 |
requireIssuedAt(Date issuedAt) | 确保解析的JWT中包含指定的iat (签发时间)。如果缺失或解析的值与指定值不匹配,将抛出异常。 |
requireExpiration(Date expiration) | 确保解析的JWT中包含指定的exp (过期时间)。如果缺失或解析的值与指定值不匹配,将抛出异常。 |
requireNotBefore(Date notBefore) | 确保解析的JWT中包含指定的nbf (生效时间)。如果缺失或解析的值与指定值不匹配,将抛出异常。 |
require(String claimName, Object value) | 确保解析的JWT中包含指定的自定义声明。如果缺失或解析的值与指定值不匹配,将抛出异常。 |
setClock(Clock clock) | 设置用于验证解析的JWT的时间戳的Clock 。默认使用DefaultClock 实例。 |
setAllowedClockSkewSeconds(long seconds) | 设置在验证exp 和nbf 声明时允许的时钟偏斜秒数。 |
setSigningKey(byte[] key) | 设置用于验证发现的JWS数字签名的签名密钥。如果JWT字符串不是JWS(无签名),则不使用此密钥。 |
setSigningKey(String base64EncodedKeyBytes) | 设置用于验证发现的JWS数字签名的签名密钥(BASE64编码)。如果JWT字符串不是JWS(无签名),则不使用此密钥。 |
setSigningKey(Key key) | 设置用于验证发现的JWS数字签名的签名密钥。如果JWT字符串不是JWS(无签名),则不使用此密钥。 |
setSigningKeyResolver(SigningKeyResolver signingKeyResolver) | 设置用于获取用于验证JWS签名的签名密钥的SigningKeyResolver 。如果JWT字符串不是JWS(无签名),则不使用此解析器。 |
setCompressionCodecResolver(CompressionCodecResolver compressionCodecResolver) | 设置用于获取用于解压缩JWT体的CompressionCodec 的CompressionCodecResolver 。如果解析的JWT未压缩,则不使用此解析器。 |
isSigned(String jwt) | 检查指定的JWT紧凑字符串是否表示一个已签名的JWT(JWS)。 |
parse(String jwt) | 根据构建器的当前配置状态解析指定的紧凑序列化JWT字符串,并返回结果JWT或JWS实例。 |
parse(String jwt, JwtHandler<T> handler) | 根据构建器的当前配置状态解析指定的紧凑序列化JWT字符串,并调用指定的handler 。 |
parsePlaintextJwt(String plaintextJwt) | 解析指定的紧凑序列化JWT字符串,并返回结果未签名的明文JWT实例。 |
parseClaimsJwt(String claimsJwt) | 解析指定的紧凑序列化JWT字符串,并返回结果未签名的Claims JWT实例。 |
parsePlaintextJws(String plaintextJws) | 解析指定的紧凑序列化JWS字符串,并返回结果明文JWS实例。 |
parseClaimsJws(String claimsJws) | 解析指定的紧凑序列化JWS字符串,并返回结果Claims JWS实例。 |
@Testpublic void test3() {String jwt = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwicm9sZSI6ImFkbWluIiwicGVybWlzc2lvbnMiOlsicmVhZCIsIndyaXRlIiwiZGVsZXRlIl0sImV4cCI6MTczNDEzODc2MCwiaWF0IjoxNzM0MTM1MTYwfQ.EWDHOGGLmy6gYUh7gpf1i2ekhZKA10DtWL_3u08-NWM";try {// 解析JWTClaims claims = Jwts.parser().setSigningKey(secretKey) // 设置签名密钥.parseClaimsJws(jwt) // 解析JWT.getBody(); // 获取Claims对象// 打印claims内容(可选)System.out.println(claims);// 提取声明String role = claims.get("role", String.class);Object permissionsObj = claims.get("permissions");if (permissionsObj instanceof List) {List<String> permissions = (List<String>) permissionsObj;for (String permission : permissions) {System.out.println(permission);}} else {System.out.println("Permissions field is not a List<String>");}} catch (SignatureException e) {System.err.println("JWT signature does not match: " + e.getMessage());} catch (Exception e) {System.err.println("An error occurred: " + e.getMessage());}}
SignatureAlgorithm
描述:一个枚举类型,用于指定JWT令牌签名的算法。
签名算法
枚举常量 | JWA算法名称 | 描述(中文) | 加密家族 | JCA名称 | 是否为JDK标准 |
---|---|---|---|---|---|
NONE | “none” | “不进行数字签名或MAC” | 无 | null | 是 |
HS256 | “HS256” | “使用SHA-256的HMAC” | HMAC | “HmacSHA256” | 是 |
HS384 | “HS384” | “使用SHA-384的HMAC” | HMAC | “HmacSHA384” | 是 |
HS512 | “HS512” | “使用SHA-512的HMAC” | HMAC | “HmacSHA512” | 是 |
RS256 | “RS256” | “使用SHA-256的RSASSA-PKCS-v1_5” | RSA | “SHA256withRSA” | 是 |
RS384 | “RS384” | “使用SHA-384的RSASSA-PKCS-v1_5” | RSA | “SHA384withRSA” | 是 |
RS512 | “RS512” | “使用SHA-512的RSASSA-PKCS-v1_5” | RSA | “SHA512withRSA” | 是 |
ES256 | “ES256” | “使用P-256和SHA-256的ECDSA” | 椭圆曲线 | “SHA256withECDSA” | 否 |
ES384 | “ES384” | “使用P-384和SHA-384的ECDSA” | 椭圆曲线 | “SHA384withECDSA” | 否 |
ES512 | “ES512” | “使用P-512和SHA-512的ECDSA” | 椭圆曲线 | “SHA512withECDSA” | 否 |
PS256 | “PS256” | “使用SHA-256和MGF1(带SHA-256)的RSASSA-PSS” | RSA | “SHA256withRSAandMGF1” | 否 |
PS384 | “PS384” | “使用SHA-384和MGF1(带SHA-384)的RSASSA-PSS” | RSA | “SHA384withRSAandMGF1” | 否 |
PS512 | “PS512” | “使用SHA-512和MGF1(带SHA-512)的RSASSA-PSS” | RSA | “SHA512withRSAandMGF1” | 否 |
使用示例
@Testpublic void test01() {Map<String, Object> claims = new HashMap<>();claims.put("role", "admin"); // 用户的角色claims.put("permissions", new String[]{"read", "write", "delete"}); // 用户的权限列表String jwt = Jwts.builder().setClaims(claims).setSubject("1234567890") // 设置主题声明,通常用作用户ID.setIssuedAt(new Date()) // 设置签发时间.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000)) // 设置过期时间.signWith(SignatureAlgorithm.HS256, secretKey) // 使用HS256算法和密钥签名.compact(); // 生成JWT字符串;System.out.println(jwt);jwt_all=jwt;}