1. 程式人生 > 程式設計 >SpringBoot整合JWT的入門指南

SpringBoot整合JWT的入門指南

目錄
  • 1.JWT
  • 2.JWT登入執行流程圖
  • 3.為什麼使用JWT?
  • 4.JWT的組成
  • 5.SpringBoot整合JWT
  • 測試
  • 總結

1.JWT

JWT(ON Web Token),為了在網路應用環境間傳遞宣告而執行的一種基於JSON的開放標準。將使用者資訊加密到token中,伺服器不儲存任何使用者資訊,伺服器通過儲存的金鑰驗證token的正確性。

優點

1.簡介:可以通過 URL POST 引數或者在 HTTP header 傳送,因為資料量小,傳輸速度也很快;

2.自包含:負載中可以包含使用者所需要的資訊,避免了多次查詢;

3.因為 Token 是以 JSON 加密的形式儲存在客戶端的,所以 JWT 是跨語言的,原則上任何 web 形式都支援;

4.不需要再服務端儲存會話資訊,特別適用於分散式微服務;

缺點

1.無法作廢已經發布的令牌;

2.不易應對資料過期;

2.JWT登入執行流程圖

SpringBoot整合JWT的入門指南

3.為什麼使用JWT?

  • 在傳統的使用者登入認證中,因為http是無狀態的,所以都是採用session+cokokie,使用者登入成功,服務端會儲存一個session,並給客戶端一個sessionId,客戶端會把sessionId儲存在cookie中,每次請求都會攜帶sessionId。cookie+session模式是儲存在記憶體中,在分散式服務中會面臨session共享問題,隨著使用者量得增加,開銷就越來越大。而JWT不需要在服務端儲存會話資訊,特別適合分散式微服務。
  • 簡潔:可以用過URL,POST引數或者在HTTP Header傳送,因為資料量小,傳輸速度也快
  • JWT支援跨語言
  • 自包含: 載荷中包含了所有使用者所需要的資訊,避免了多次查詢資料庫。

4.JWT的組成

JWT由三部分構成,類似於如下:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJscyIsImV4cCI6MTYyNDU5Nzc5Nn0.4kwT1elZCb_k2D7AxbuFHM35VmBK4PcmLaqHhcHEq4_wVe8GVO8ODypGSKksTs-hraBopBCm2IC9EC2rO-GHng

第一部分為頭部(header),承載兩部分資訊

宣告型別(JWT)

宣告加密演算法,預設為HMAwww.cppcns.comC SHA256

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

使用Base64加密後

第二部分為payload(載荷),存放有效資訊的地方,這些有效資訊分為三部分:

  • 標準中註冊的宣告
  • 公共的宣告
  • 私有的宣告

其中,標準中註冊的宣告 (建議但不強制使用)包括如下幾個部分 :

  • iss: jwt簽發者;
  • sub: jwt所面向的使用者;
  • aud: 接收jwt的一方;
  • exp: jwt的過期時間,這個過期時間必須要大於簽發時間;
  • nbf: 定義在什麼時間之前,該jwt都是不可用的;
  • iat: jwt的簽發時間;
  • jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊

公共的宣告部分:

公共的宣告可以新增任何資訊,一般新增使用者的相關資訊或其他業務需要的必要資訊,但不建議新增銘感資訊,因為在客戶端可解密。

私有的宣告部分:

私有的宣告是提供者和消費者共同定義的宣告,不建議存放敏感資訊,因為base64是對稱解密的,意味著該部分資訊可以歸類為明文資訊。

第三部分為signature(簽證)

var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);

//金鑰就是我們定義的secret,加密後得到簽證
var signature = HMACSHA256(encodedString,'金鑰');

5.SpringBoot整合JWT

引入依賴

  <!--JWT-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.7.0</version>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>-jwt</artifactId>
            <version>3.4.0</version>
        </dependency>
          <!--StringUtils工具包-->
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
        <!--ConfigurationProperties出現異常-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

配置application.yml檔案

server:
  port: 8888
spring:
  jwt:
    #過期時間
    expireTime: 1800000
    #加密金鑰
    secret: lsyyp5201314
    #token返回頭部
    header: LOGINTOKEN

JWT工具類

package org.best.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.TokenExpiredException;
import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.Date;

@ConfigurationProperties(prefix = "spring.jwt")
public class JWTUtils {

    public static String header;
    private static String secret;
    private static String expireTime;

    /**
     * 生成token
     * @param sub 使用者唯一資訊
     * @return token
     */
    public  static   String createToken(String sub){
        return JWT
                .create()
                .withSubject(sub)
                .withExpiresAt(new Date(System.currentTimeMillis()+Long.parseLong(expireTime)))
                .sign(Algorithm.HMAC512(secret));
www.cppcns.com    }

    /**
     * 根據token獲取使用者資訊
     * @param token
     * @return 使用者資訊
     */
    public static String validateToken(String token){
        return JWT
                .require(Algorithm.HMAC512(secret))
                .build()
                .verify(token)
                .getSubject();
    }

    /**
     * 檢驗Token是否需要重新整理
     * @param token
     * @return
     */
    public static boolean refreshToken(String token) {
        Date expireDate = null;
        try {
            expireDate = JWT
                    .require(Algorithm.HMAC512(secret))
                    .build()
                    .verify(token)
                    .getExpiresAt();
        } catch (TokenExpiredException e) {
            return true;
        }
        return (expireDate.getTime()-System.currentTimeMillis())<0;
    }

    public void setHeader(String header) {
        this.header = header;
    }

    public String getSecret() {
        return secret;
    }

    public void setSecret(String secret) {
        this.secret = secret;
    }

    public String getExpireTime() {
        return expireTime;
    }

    public void setExpireTime(String expireTime) {
        this.expireTime = expireTime;
    }
}

自定義攔截器

package org.best.config;

import org.apache.commons.lang.StringUtils;
import org.best.common.TokenIsNullException;
import org.best.common.TokenValidateException;
import org.best.util.JWTUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception {
        String logintoken = request.getHeader("LOGINTOKEN");
        //如果token為空
        if (StringUtils.isBlank(logintoken)){
            throw new TokenIsNullException("請登入");
        }
        //校驗Token
        String sub = JWTUtils.validateToken(logintoken);
        if (StringUtils.isBlank(sub)){
            throw new TokenValidateException("token校驗失敗");
        }

        //更新token有效期(生產新token)
        if (JWTUtils.refreshToken(logintoken)){
            String token = JWTUtils.createToken(sub);
            response.setHeader(JWTUtils.header,token);
        }

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request,Object handler,ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request,Exception ex) throws Exception {

    }
}

註冊攔截器

package org.best.config;http://www.cppcns.com

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry
                .addInterceptor(new LoginInterceptor())
                .addPathPatterns("/find")
                .excludePathPatterns("/login");
    }
}

自定義異常

package org.best.common;

/**
 * Token校驗異常
 */
public class TokenValidateException extends RuntimeException {
    public TokenValidateException() {
    }

    public TokenValidateException(String message) {
        super(message);
    }
}

package org.best.common;

/**
 * Token為空異常
 */
public class TokenIsNullException extends RuntimeException{
    public TokenIsNullException() {
    }

    public TokenIsNullException(String message) {
        super(message);
    }
}

自定義Controller

package org.best.controller;

import org.best.pojo.User;
import org.best.util.JWTUtils;
import org.springframework.web.bind.annotati客棧on.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;

@RestController
public class LoginController {
    @GetMapping("/login")
    public String login(User user,HttpServletResponse response){
        //這裡就不做資料庫查詢了

        //根據使用者id生成token
        String token = JWTUtils.createToken(String.valueOf(user.getId()));
        //將token存入HTTP響應頭中
        response.setHeader(JWTUtils.header,token);
        return user.toString();
    }

    @GetMapping("/find")
    public String find(){
        return "success";
    }
}

測試

登入介面

SpringBoot整合JWT的入門指南

我們來測試下find 介面 ,不帶token會出現啥情況

SpringBoot整合JWT的入門指南

帶上token

SpringBoot整合JWT的入門指南

總結

到此這篇關於SpringBoot整合JWT的文章就介紹到這了,更多相關SpringBoot整合JWT內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!