使用jjwt生成JWT(JSON Web Tokens)

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

相關文章
相關標籤/搜索