This commit is contained in:
Looly 2021-06-10 09:16:45 +08:00
parent 227a740fab
commit 928866711b
5 changed files with 317 additions and 0 deletions

View File

@ -0,0 +1,56 @@
package cn.hutool.json.jwt;
import cn.hutool.core.lang.Assert;
import cn.hutool.json.JSONUtil;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
/**
* Claims 认证
*
* @author looly
*/
public class Claims implements Serializable {
private static final long serialVersionUID = 1L;
private final Map<String, Object> claimMap;
public Claims() {
this.claimMap = new HashMap<>();
}
/**
* 增加Claims属性
*
* @param name 属性名
* @param value 属性值
*/
protected void setClaim(String name, Object value) {
Assert.notNull(name, "Name must be not null!");
if (value == null) {
claimMap.remove(name);
return;
}
claimMap.put(name, value);
}
/**
* 获取Claims数据Map
*
* @return map
*/
protected Map<String, Object> getClaimMap() {
return this.claimMap;
}
/**
* 获取Claims的JSON字符串形式
*
* @return JSON字符串
*/
public String getClaimsJson() {
return JSONUtil.toJsonStr(getClaimMap());
}
}

View File

@ -0,0 +1,48 @@
package cn.hutool.json.jwt;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.StrUtil;
import java.nio.charset.Charset;
/**
* JSON Web Token (JWT)基于JSON的开放标准(RFC 7519)用于在网络应用环境间传递声明<br>
*
* 结构xxxxx.yyyyy.zzzzz
* <ul>
* <li>header主要声明了JWT的签名算法</li>
* <li>payload主要承载了各种声明并传递明文数据</li>
* <li>signture拥有该部分的JWT被称为JWS也就是签了名的JWS</li>
* </ul>
*
* <p>
* 详细介绍见https://www.jianshu.com/p/576dbf44b2ae
* </p>
*
* @author looly
*/
public class JWT {
private Charset charset;
private Signer signer;
private final JWTHeader header;
private final JWTPayload payload;
public JWT() {
this.header = new JWTHeader();
this.payload = new JWTPayload();
}
/**
* 签名生成JWT字符串
*
* @return JWT字符串
*/
public String sign(){
final String headerBase64 = Base64.encodeUrlSafe(this.header.getClaimsJson(), charset);
final String payloadBase64 = Base64.encodeUrlSafe(this.payload.getClaimsJson(), charset);
final String sign = signer.sign(headerBase64, payloadBase64);
return StrUtil.format("{}.{}.{}", headerBase64, payloadBase64, sign);
}
}

View File

@ -0,0 +1,59 @@
package cn.hutool.json.jwt;
import java.util.Map;
/**
* JWT头部信息
*
* @author looly
*/
public class JWTHeader extends Claims {
private static final long serialVersionUID = 1L;
//Header names
/**
* 加密算法通常为HMAC SHA256HS256
*/
public static String ALGORITHM = "alg";
/**
* 声明类型一般为jwt
*/
public static String TYPE = "typ";
/**
* 内容类型content type
*/
public static String CONTENT_TYPE = "cty";
/**
* jwk的ID编号
*/
public static String KEY_ID = "kid";
/**
* 增加kid头信息
*
* @param keyId kid
* @return this
*/
public JWTHeader addKeyId(String keyId) {
setClaim(KEY_ID, keyId);
return this;
}
/**
* 增加自定义JWT认证头
*
* @param headerClaims 头信息
* @return this
*/
public JWTHeader addHeaders(Map<String, ?> headerClaims) {
if (headerClaims == null) {
return this;
}
for (Map.Entry<String, ?> entry : headerClaims.entrySet()) {
setClaim(entry.getKey(), entry.getValue());
}
return this;
}
}

View File

@ -0,0 +1,148 @@
package cn.hutool.json.jwt;
import java.util.Date;
import java.util.Map;
/**
* JWT载荷信息<br>
* 载荷就是存放有效信息的地方这个名字像是特指飞机上承载的货品这些有效信息包含三个部分:
*
* <ul>
* <li>标准中注册的声明</li>
* <li>公共的声明</li>
* <li>私有的声明</li>
* </ul>
* <p>
* 详细介绍见https://www.jianshu.com/p/576dbf44b2ae
*
* @author looly
*/
public class JWTPayload extends Claims {
private static final long serialVersionUID = 1L;
/**
* jwt签发者
*/
public static String ISSUER = "iss";
/**
* jwt所面向的用户
*/
public static String SUBJECT = "sub";
/**
* 接收jwt的一方
*/
public static String AUDIENCE = "aud";
/**
* jwt的过期时间这个过期时间必须要大于签发时间
*/
public static String EXPIRES_AT = "exp";
/**
* 定义在什么时间之前该jwt都是不可用的.
*/
public static String NOT_BEFORE = "nbf";
/**
* jwt的签发时间
*/
public static String ISSUED_AT = "iat";
/**
* jwt的唯一身份标识主要用来作为一次性token,从而回避重放攻击
*/
public static String JWT_ID = "jti";
/**
* 设置 jwt签发者("iss")的Payload值
*
* @param issuer jwt签发者
* @return this
*/
public JWTPayload setIssuer(String issuer) {
setClaim(ISSUER, issuer);
return this;
}
/**
* 设置jwt所面向的用户("sub")的Payload值
*
* @param subject jwt所面向的用户
* @return this
*/
public JWTPayload setSubject(String subject) {
setClaim(SUBJECT, subject);
return this;
}
/**
* 设置接收jwt的一方("aud")的Payload值
*
* @param audience 接收jwt的一方
* @return this
*/
public JWTPayload setAudience(String... audience) {
setClaim(AUDIENCE, audience);
return this;
}
/**
* Add a specific Expires At ("exp") claim to the Payload.
* 设置jwt的过期时间("exp")的Payload值这个过期时间必须要大于签发时间
*
* @param expiresAt jwt的过期时间
* @return this
* @see #setIssuedAt(Date)
*/
public JWTPayload setExpiresAt(Date expiresAt) {
setClaim(EXPIRES_AT, expiresAt);
return this;
}
/**
* 设置不可用时间点界限("nbf")的Payload值
*
* @param notBefore 不可用时间点界限在这个时间点之前jwt不可用
* @return this
*/
public JWTPayload setNotBefore(Date notBefore) {
setClaim(NOT_BEFORE, notBefore);
return this;
}
/**
* 设置jwt的签发时间("iat")
*
* @param issuedAt 签发时间
* @return this
*/
public JWTPayload setIssuedAt(Date issuedAt) {
setClaim(ISSUED_AT, issuedAt);
return this;
}
/**
* 设置jwt的唯一身份标识("jti")
*
* @param jwtId 唯一身份标识
* @return this
*/
public JWTPayload setJWTId(String jwtId) {
setClaim(JWT_ID, jwtId);
return this;
}
/**
* 增加自定义JWT认证载荷信息
*
* @param payloadClaims 载荷信息
* @return this
*/
public JWTPayload addPayload(Map<String, ?> payloadClaims) {
if (payloadClaims == null) {
return this;
}
for (Map.Entry<String, ?> entry : payloadClaims.entrySet()) {
setClaim(entry.getKey(), entry.getValue());
}
return this;
}
}

View File

@ -0,0 +1,6 @@
package cn.hutool.json.jwt;
public interface Signer {
String sign(String header, String payload);
}