玩转springboot2.x之整合JWT篇

如何学习JWT ?

在这里咱们来探讨一下如何学习一门新的技术,我我的总结为 RSA。html

  1. R:read 去读官方文档 。
  2. S:search 谷歌或百度先关技术文章或github 去搜索先关信息。
  3. A:ask:能够向技术大牛请教或和本身的同事同窗进行探讨。

首先让咱们JWT 官网一探究竟。https://jwt.iojava

 

 

JWT 介绍

本身英文很差 使用百度翻译内容以下:git

JSON Web令牌(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于在各方之间做为JSON对象安全地传输信息。该信息能够被验证和信任,由于它是数字签名的。JWTS能够使用秘密(使用HMAC算法)或公钥/私钥对使用RSA或ECDSA来签名。github

虽然JWTS能够加密,但也提供保密各方之间,咱们将重点放在签名令牌。签名的令牌能够验证包含在其中的声明的完整性,而加密的令牌隐藏这些声明以防其余各方。当令牌使用公钥/私钥对签名时,签名也证实只有持有私钥的方才是签名的方。算法

 

JWT 使用介绍

接下来咱们开始学习若是使用JWT,经过点击上图中 LEARN MORE ABOUT JWT 显示以下图:而后点击START USING THE TOOLspring

 

以下图所示 选择对应的语言的jwt 使用教程。咱们这里介绍是是 标注有:maven:com.auth0 java-jwt 的版本。安全

 

 

查看 jwt github 示例教程和源码。 https://github.com/auth0/java-jwtspringboot

在README.md 文件中有使用介绍和示例程序。服务器

 

 

 

使用jwt 咱们须要处理三块内容以下:maven

  1. 头部信息
  2. 载荷信息
  3. 签名信息

头部信息

 头部信息由2部分组成

  1. 令牌的类型,即JWT
  2. 使用的签名算法 例如HMAC SHA256或RSA。

例如:

{
  "alg": "HS256",
  "typ": "JWT"
}

而后,这个JSON被编码为Base64Url,造成JWT的第一部分。

载荷信息

其中包含声明(claims)。声明能够存放实体(一般是用户)和其余数据的声明,声明包括3种类型

  1. 已注册声明
  2. 公开声明
  3. 私有声明

已注册声明

这些是一组预约义声明,不是强制性的,但建议使用,以提供一组有用的,可互操做的声明。其中一些是: iss(发行人), exp(到期时间),(主题), aud(观众)

公开声明

能够参考 IANA JSON Web令牌注册表 查看公共的声明

私有声明

根据根据本身的业务须要自定义的一些数据格式。

示例有效负载能够是:

{

"sub": "1234567890",

"name": "John Doe",

"admin": true

}

签名信息

 这个部分须要base64加密后的header和base64加密后的payload使用.链接组成的字符串,而后经过header中声明的加密方          式进行加盐secret组合加密,而后就构成了jwt的第三部分。

例如,若是要使用HMAC SHA256算法,将按如下方式建立签名:

HMACSHA256(

base64UrlEncode(header) + "." +

base64UrlEncode(payload),

secret)

 

使用springboot 集成jwt 操做步骤

第一步引入JWT 依赖到pom.xml中

<dependency>
		    <groupId>com.auth0</groupId>
		    <artifactId>java-jwt</artifactId>
		    <version>3.4.1</version>
</dependency>

 

咱们经过三个方法来演示如何使用JWT

  1. createToken() 建立不携带自定义信息的 token
  2. createTokenWithClaim() 建立携带自定义信息的 token
  3. verifyToken() 验证咱们的token信息并解析token中的内容

生成JWT token

构建头部信息

Map<String, Object> map = new HashMap<String, Object>();
map.put("alg", "HS256");
map.put("typ", "JWT");

构建密钥信息 

Algorithm algorithm = Algorithm.HMAC256("secret");

 咱们经过定义注册和自定义声明 并组合头部信息和密钥信息生成jwt token 

String token = JWT.create()
		    	.withHeader(map)
		    	/*设置 载荷 Payload*/
		    	.withClaim("loginName", "zhuoqianmingyue")
		        .withIssuer("SERVICE")//签名是有谁生成 例如 服务器
		        .withSubject("this is test token")//签名的主题
		        //.withNotBefore(new Date())//该jwt都是不可用的时间
		        .withAudience("APP")//签名的观众 也能够理解谁接受签名的
		        .withIssuedAt(nowDate) //生成签名的时间
		        .withExpiresAt(expireDate)//签名过时的时间
		        /*签名 Signature */
		        .sign(algorithm);

 

验证 JWT Token

构建密钥信息

Algorithm algorithm = Algorithm.HMAC256("secret");

 经过密钥信息和签名的发布者的信息生成JWTVerifier (JWT验证类) 

JWTVerifier verifier = JWT.require(algorithm)
		        .withIssuer("SERVICE")
		        .build();

经过JWTVerifier 的verify获取 token中的信息。 

DecodedJWT jwt = verifier.verify(token);

以下面代码所示就能够获取到咱们以前生成token的 签名的主题,观众 和自定义的声明信息。

String subject = jwt.getSubject();
		    List<String> audience = jwt.getAudience();
		    Map<String, Claim> claims = jwt.getClaims();

具体代码以下: 

package com.ljk.springBootLearn.jwt;
 
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
 
public class JWTDemo {
    public String createToken() {
        
        try {
            String secret = "secret";//token 密钥
            Algorithm algorithm = Algorithm.HMAC256("secret");
            //头部信息
            Map<String, Object> map = new HashMap<String, Object>();
            map.put("alg", "HS256");
            map.put("typ", "JWT");
            
            Date nowDate = new Date();
            Date expireDate = getAfterDate(nowDate,0,0,0,2,0,0);//2小过时
        
            String token = JWT.create()
                /*设置头部信息 Header*/
                .withHeader(map)
                /*设置 载荷 Payload*/
                .withIssuer("SERVICE")//签名是有谁生成 例如 服务器
                .withSubject("this is test token")//签名的主题
                //.withNotBefore(new Date())//定义在什么时间以前,该jwt都是不可用的.
                .withAudience("APP")//签名的观众 也能够理解谁接受签名的
                .withIssuedAt(nowDate) //生成签名的时间
                .withExpiresAt(expireDate)//签名过时的时间
                /*签名 Signature */
                .sign(algorithm);
            return token;
        } catch (JWTCreationException exception){
            exception.printStackTrace();
        }
        return null;
    }
    public String createTokenWithClaim() {
        
        try {
            Algorithm algorithm = Algorithm.HMAC256("secret");
            Map<String, Object> map = new HashMap<String, Object>();
            Date nowDate = new Date();
            Date expireDate = getAfterDate(nowDate,0,0,0,2,0,0);//2小过时
            map.put("alg", "HS256");
            map.put("typ", "JWT");
            String token = JWT.create()
                /*设置头部信息 Header*/
                .withHeader(map)
                /*设置 载荷 Payload*/
                .withClaim("loginName", "lijunkui")
                .withIssuer("SERVICE")//签名是有谁生成 例如 服务器
                .withSubject("this is test token")//签名的主题
                //.withNotBefore(new Date())//定义在什么时间以前,该jwt都是不可用的.
                .withAudience("APP")//签名的观众 也能够理解谁接受签名的
                .withIssuedAt(nowDate) //生成签名的时间
                .withExpiresAt(expireDate)//签名过时的时间
                /*签名 Signature */
                .sign(algorithm);
            return token;
        } catch (JWTCreationException exception){
            exception.printStackTrace();
        }
        return null;
    }
      /**
         * 返回必定时间后的日期
         * @param date 开始计时的时间
         * @param year 增长的年
         * @param month 增长的月
         * @param day 增长的日
         * @param hour 增长的小时
         * @param minute 增长的分钟
         * @param second 增长的秒
         * @return
         */
        public  Date getAfterDate(Date date, int year, int month, int day, int hour, int minute, int second){
            if(date == null){
                date = new Date();
            }
            
            Calendar cal = new GregorianCalendar ();
            
            cal.setTime(date);
            if(year != 0){
                cal.add(Calendar.YEAR, year);
            }
            if(month != 0){
                cal.add(Calendar.MONTH, month);
            }
            if(day != 0){
                cal.add(Calendar.DATE, day);
            }
            if(hour != 0){
                cal.add(Calendar.HOUR_OF_DAY, hour);
            }
            if(minute != 0){
                cal.add(Calendar.MINUTE, minute);
            }
            if(second != 0){
                cal.add(Calendar.SECOND, second);
            }
            return cal.getTime();
        }
    public void verifyToken(String token) {
        try {
            Algorithm algorithm = Algorithm.HMAC256("secret");
            JWTVerifier verifier = JWT.require(algorithm)
                .withIssuer("SERVICE")
                .build(); //Reusable verifier instance
            DecodedJWT jwt = verifier.verify(token);
            String subject = jwt.getSubject();
            Map<String, Claim> claims = jwt.getClaims();
            Claim claim = claims.get("loginName");
            System.out.println(claim.asString());
            List<String> audience = jwt.getAudience();
            System.out.println(subject);
            System.out.println(audience.get(0));
        } catch (JWTVerificationException exception){
            exception.printStackTrace();
        }
    }
    
    public static void main(String[] args) {
        JWTDemo demo = new JWTDemo();
        //String createToken = demo.createToken();
        String createTokenWithClaim = demo.createTokenWithClaim();
        demo.verifyToken(createTokenWithClaim);
    }
}

 

参考文献:http://www.javashuo.com/article/p-uxridfao-cg.html 

另外也能够关注一下 个人GitHub项目: springbootexamples 进行学习