使用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.html

使用jjwt生成JWT(JSON Web Tokens)

上一篇:JS进阶篇1---函数节流(throttle)


下一篇:《图解HTTP》HTTP首部(1)