1,添加依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
2,实现代码
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.SignatureException;
import org.apache.commons.lang3.StringUtils;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
/**
* @Description JwtUtil
* @Author dsf
* @Date 2020/12/19 8:49
* @Version V1.0
**/
public class JwtUtil {
/*
* 加密秘钥
* */
private static String SECRET_BASE64_KEY = "LX2lnm1cyaHUuPHWxb02Txzl5yTx2lqfRthIFrHO+zQ=" ;
/**
* 生成签名的时候使用的秘钥.
* 注意:切记这个秘钥不能外露哦。它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
*/
public static SecretKey generalKey() {
byte[] encodedKey = java.util.Base64.getDecoder().decode(SECRET_BASE64_KEY);
return new SecretKeySpec(encodedKey, SignatureAlgorithm.HS256.getJcaName());
}
/**
* 创建头部(第一部分)
* 通常包含两部分的信息: token的类型, 如JWT, 以及token使用的加密算法, 如 HMAC SHA256或者RSA.
* {
* "alg": "HS256",
* "typ": "JWT"
* }
* 接下来, 这部分JSON内容经过Base64Url 编码来组成JWT的第一部分结构信息.
* ==================================================================
* 创建负载(第二部分)
* Payload包含claims. Claims是一些实体(通常指用户)的状态信息和其他元数据。
* 有三种类型的claims: registered, public, 和 private
* - Registered claims: 这些claims是预先定义的,在JWT中并不强制使用这些claims,但是推荐使用这些有效而又约定俗成的claims,
* 比如: iss (issuer 签发者), exp(expiration time 过期时间), sub (subject 面向的用户), aud (audience 接收方 )
* - Public claims: 这些claims可以由开发人员*定义,但为了避免出现冲突,应该在 IANA JSON Web Token Registry中定义他们,
* 或者将其定义为包含防止冲突命名空间的URI。
* -------------------------------
* IANA JSON Web Token Registry
* -------------------------------
* Claim Name | Claim Description
* iss Issuer
* sub Subject
* aud Audience
* exp Expiration Time
* nbf Not Before
* iat Issued At
* jti JWT ID
* name Full name
* given_name Given name(s) or first name(s)
* family_name Surname(s) or last name(s)
* middle_name Middle name(s)
* nickname Casual name
* preferred_username Shorthand name by which the End-User wishes to be referred to
* profile Profile page URL
* picture Profile picture URL
* website Web page or blog URL
* email Preferred e-mail address
* email_verified True if the e-mail address has been verified; otherwise false
* gender Gender
* birthdate Birthday
* zoneinfo Time zone
* locale Locale
* phone_number Preferred telephone number
* phone_number_verified True if the phone number has been verified; otherwise false
* address Preferred postal address
* updated_at Time the information was last updated
* azp Authorized party - the party to which the ID Token was issued
* nonce Value used to associate a Client session with an ID Token
* auth_time Time when the authentication occurred
* at_hash Access Token hash value
* c_hash Code hash value
* acr Authentication Context Class Reference
* amr Authentication Methods References
* sub_jwk Public key used to check the signature of an ID Token
* cnf Confirmation
* sip_from_tag SIP From tag header field parameter value
* sip_date SIP Date header field value
* sip_callid SIP Call-Id header field value
* sip_cseq_num SIP CSeq numeric header field parameter value
* sip_via_branch SIP Via branch header field parameter value
* orig Originating Identity String
* dest Destination Identity String
* mky Media Key Fingerprint String
* events Security Events
* toe Time of Event
* txn Transaction Identifier
* rph Resource Priority Header Authorization
* sid Session ID
* vot Vector of Trust value
* vtm Vector of Trust trustmark URL
* attest Attestation level as defined in SHAKEN framework
* origid Originating Identifier as defined in SHAKEN framework
* act Actor
* scope Scope Values
* client_id Client Identifier
* - Private claims: 这里放置的是自定义claims,若既没有在registered 也没有在 public中定义的话,双方可以使用此claims 来进行信息之间的交换。
* {
* "sub": "1234567890",
* "name": "John Doe",
* "admin": true
* }
* 负载(payload)部分经过 Base64Url 编码来组成JWT的第二部分结构信息.
* ==================================================================
* 创建签名.使用经过编码后的头部(header)和负载(payload)以及一个密钥,使用在头部(header)中指定的算法进行签名。
* 该签名是用户验证JWT的请求发送者以及确保数据信息在传输过程中的消息是未经篡改的。
* WT的最终输出,是由以.分隔的三段Base64编码后的字符串,可以在HTML和HTTP环境中轻松的传递,而与基于XML的标准如SAML相比 JWT则更加紧凑。
* -------------------------------------------------------------------------------------------------------------
* @param claims 创建payload的私有声明(根据特定的业务需要添加,如果要拿这个做验证,一般是需要和jwt的接收方提前沟通好验证方式)
* */
public static String createJWT(Map<String,?> claims,String subject,String issuer,String audience,java.util.Date issuedAt
,java.util.Date notBefore,java.util.Date expiration) {
JwtBuilder builder = Jwts.builder() ;
//jti:是JWT的唯一标识,根据业务需要,这个可以设置为一个不重复的值,主要用来作为一次性token,从而回避重放***
builder.setId(UUID.randomUUID().toString()) ;
if(claims != null && claims.size() > 0){
//如果有私有声明,一定要先设置,因为一旦写在标准的声明赋值之后,就是覆盖了那些标准的声明
builder.setClaims(claims) ;
}
if(StringUtils.isNotBlank(subject)){
//sub:代表这个JWT的主体,即它的所有人,这个是一个json格式的字符串,可以存放什么userid,roldid之类的,作为什么用户的唯一标志
builder.setSubject(subject) ;
}
if(StringUtils.isNotBlank(issuer)){
//iss:jwt签发人
builder.setIssuer(issuer) ;
}
if(issuedAt != null){
//iat:jwt的签发时间
builder.setIssuedAt(issuedAt) ;
}
if(StringUtils.isNotBlank(audience)){
//aud:受众,用来标识收件人
builder.setAudience(audience) ;
}
if(notBefore != null){
//nbf:jwt生效时间
builder.setNotBefore(notBefore) ;
}
if(expiration != null){
//exp:jwt的失效时间
builder.setExpiration(expiration) ;
}
//设置签名使用的签名算法和签名使用的秘钥
builder.signWith(generalKey(),SignatureAlgorithm.HS256) ;
//生成jwt数据
return builder.compact() ;
}
/**
* 解析JWT字符串
* @throws Exception
*/
public static Claims parseJWT(String jwt) throws Exception {
SecretKey key = generalKey(); //签名秘钥,和生成的签名的秘钥一模一样
Claims claims = Jwts.parserBuilder()
.setSigningKey(key) //设置签名的秘钥
.build()
.parseClaimsJws(jwt).getBody(); //设置需要解析的jwt
return claims;
}
public static void main(String[] args) throws Exception {
Map<String,String> claims = new HashMap<>() ;
claims.put("name","123456") ;
//签发时间
LocalDateTime issuedAt = LocalDateTime.now() ;
//过期时间(10分钟)
LocalDateTime expiration = issuedAt.plus(10,ChronoUnit.MINUTES) ;
//2分钟后生效
LocalDateTime notBefore = issuedAt.plus(2,ChronoUnit.MINUTES) ;
java.util.Date issuedAtDate = java.util.Date.from(issuedAt.atZone(ZoneId.of("Asia/Shanghai")).toInstant()) ;
java.util.Date notBeforeDate = java.util.Date.from(notBefore.atZone(ZoneId.of("Asia/Shanghai")).toInstant()) ;
java.util.Date expirationDate = java.util.Date.from(expiration.atZone(ZoneId.of("Asia/Shanghai")).toInstant()) ;
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(issuedAtDate));
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(notBeforeDate));
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(expirationDate));
String subject = "{\"userId\":\"adb\"}" ;
String issuer = "issuer" ;
String audience = "audience" ;
////////////////////创建JWT///////////////
String jwt = createJWT(claims,subject, issuer,audience,issuedAtDate,notBeforeDate,expirationDate) ;
System.out.println("jwt->" + jwt);
//解析JWT里面的数据
String[] ar = jwt.split("\\.") ;
for(String item : ar){
System.out.println(new String(Base64.getUrlDecoder().decode(item)));
}
////////////////////解析JWT///////////////
try{
Claims c = parseJWT(jwt) ;
System.out.println(c.getId());
System.out.println(c.getIssuedAt());
System.out.println(c.getSubject());
System.out.println(c.getIssuer());
System.out.println(c.get("userId", String.class));
}catch (PrematureJwtException e){
//notBefore: 提示该JWT的接收时间还没到
e.printStackTrace();
}catch (ExpiredJwtException e){
e.printStackTrace();
}catch ( UnsupportedJwtException e){
e.printStackTrace();
}catch (MalformedJwtException e){
e.printStackTrace();
} catch (SignatureException e){
e.printStackTrace();
}catch (IllegalArgumentException e){
e.printStackTrace();
}
}
}
http://jwtio.online/introduction.html
使用jjwt生成JWT(JSON Web Tokens)