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.htmlhtml