最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot整合JWT(JSON?Web?Token)生成token與驗證的流程及示例

 更新時間:2024年07月16日 09:28:35   作者:辛苦cv的小hui  
JSON Web Token(JWT)是一種開放的標(biāo)準(zhǔn)(RFC 7519),定義了一種緊湊的、自包含的方式來安全地在各方之間傳輸信息作為JSON對象,這篇文章主要給大家介紹了關(guān)于SpringBoot整合JWT(JSON?Web?Token)生成token與驗證的相關(guān)資料,需要的朋友可以參考下

JWT

什么是JWT

JWT(JSON Web Token)是是目前最流行的跨域認(rèn)證解決方案。它通常被用于對用戶進行身份驗證和授權(quán)。JWT由三部分組成,每個部分之間使用"."進行分隔,這三部分分別是:

  • Header: 包含了聲明類型和JWT的加密算法
  • Payload: 負(fù)載,存放有效信息的地方。這些有效信息包含三個部分:標(biāo)準(zhǔn)中注冊的聲明、公共的聲明 和 私有的聲明。
  • Signature: 簽名信息。

官網(wǎng)地址:https://jwt.io/introduction

JWT使用流程

確定要傳遞的信息:

  • 首先,確定您想在JWT中傳遞的信息。這通常包括用戶的唯一標(biāo)識符(如用戶ID)、角色、用戶名等。

生成JWT:

  • 生成Header:Header是JWT的第一部分,它描述了JWT的類型("typ")和加密算法("alg")。
  • 生成Payload:Payload是JWT的第二部分,包含了編碼后的信息。在Payload中,通常還會添加一個"iat"字段,表示JWT的簽發(fā)時間(Issued At)
  • 生成Signature:使用一個密鑰(Secret Key)對Header和Payload進行簽名,以確保它們的完整性和真實性。簽名是通過指定的算法(如HMAC SHA256)生成的。
  • 將Base64編碼后的Header、Payload和Signature用點號(.)連接起來,形成一個完整的JWT字符串。
  • 例如:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

JWT傳輸:

  • 服務(wù)器將生成的JWT發(fā)送給客戶端,通常通過在HTTP響應(yīng)的頭部設(shè)置Authorization字段的值為Bearer JWT。

客戶端保存JWT:

  • 客戶端在接收到JWT后,將其保存在本地,通常存儲在Cookie、LocalStorage或SessionStorage中。

客戶端發(fā)送JWT:

  • 客戶端在每次請求服務(wù)器時,將JWT帶在請求的頭部,通過Authorization字段將JWT發(fā)送給服務(wù)器。
  • 請求頭的格式通常為:Authorization: Bearer JWT

服務(wù)器驗證JWT:

  • 服務(wù)器接收到請求后,從請求的頭部中獲取JWT,并進行驗證。
  • 驗證的過程包括解析JWT、驗證簽名的完整性和真實性、檢查JWT是否過期等。
  • 如果驗證通過,服務(wù)器會進一步解析Payload中的數(shù)據(jù),獲取用戶的相關(guān)信息。

服務(wù)器響應(yīng):

  • 如果JWT驗證通過,服務(wù)器會繼續(xù)處理請求,并返回相應(yīng)的數(shù)據(jù)。
  • 如果JWT驗證失敗,服務(wù)器會返回相應(yīng)的錯誤信息。

通過以上流程,JWT實現(xiàn)了一種安全、緊湊、自包含的令牌傳遞機制,用于在客戶端和服務(wù)器之間安全地傳輸用戶信息。

springboot引入jwt相關(guān)依賴

要在Spring Boot項目中引入jjwt,你需要在你的pom.xml(如果你使用Maven)或build.gradle(如果你使用Gradle)文件中添加相應(yīng)的依賴。

maven:

<!--引入jwt相關(guān)包來生成token-->
        <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>

Gradle:

dependencies {  
    implementation 'io.jsonwebtoken:jjwt-api:0.11.2' 
    runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2'   
    runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.2' 
}

Token的使用示例:

工具類

先寫一個創(chuàng)建Token的方法,再寫一個驗證token的方法

import com.certificateManage.common.R;
import com.certificateManage.controller.exception.TokenException;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;

import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Date;

//用于生成token的類
public class JwtTokenUtil {

    private static final String SECRET_KEY = "abcdefgabcdefghijklmnopqrstuvwxyz"; // 密鑰
    private static final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;//加密方式
    //ttMillis是token持續(xù)時間
    public static String createToken(String id, long ttlMillis) {
        // 簽名密鑰
        byte[] secretKeyBytes = SECRET_KEY.getBytes(StandardCharsets.UTF_8);
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyBytes, signatureAlgorithm.getJcaName());

        // 設(shè)置JWT的簽發(fā)時間和過期時間
        Date now = new Date();
        Date expiration = new Date(now.getTime() + ttlMillis);
        // 使用指定的密鑰和算法生成JWT
        return Jwts.builder()
                .setSubject(id)//設(shè)置id
                .setIssuedAt(now) // 設(shè)置簽發(fā)時間
                .setExpiration(expiration) // 設(shè)置過期時間
                .signWith(secretKeySpec,signatureAlgorithm) // 設(shè)置簽名密鑰和簽名算法
                .compact(); // 生成JWT字符串
    }


    //驗證token如果正確返回用戶id
    public static R checkToken(String token){
        try {
            // 解析token  
            Claims claims = Jwts.parser()
                    .setSigningKey(Keys.hmacShaKeyFor(SECRET_KEY.getBytes(StandardCharsets.UTF_8))) // 設(shè)置密鑰  
                    .parseClaimsJws(token) // 解析token  
                    .getBody(); // 獲取負(fù)載  

            // 驗證負(fù)載中的信息  
            String subject = claims.getSubject(); // 獲取用戶ID或其他信息  
            Date expiration = claims.getExpiration(); // 獲取過期時間  
            System.out.println(expiration.toString());

            // 驗證token是否過期  
            if (expiration.before(new Date())) {
                throw new TokenException("token失效");
            }
            return R.success(subject);

        } catch (ExpiredJwtException e) {
            // 當(dāng)token過期時,會捕獲到ExpiredJwtException異常  
            return R.error("Token已過期");
        } catch (UnsupportedJwtException e) {
            // 當(dāng)token不受支持時,會捕獲到UnsupportedJwtException異常  
            return R.error("Token不受支持");
        } catch (MalformedJwtException e) {
            // 當(dāng)token格式錯誤時,會捕獲到MalformedJwtException異常  
            return R.error("Token格式錯誤");
        } catch (SignatureException e) {
            // 當(dāng)token簽名錯誤時,會捕獲到SignatureException異常  
            return R.error("Token簽名錯誤");
        } catch (IllegalArgumentException e) {
            // 當(dāng)token為空或非法時,會捕獲到IllegalArgumentException異常  
            return R.error("Token為空或非法");
        } catch (TokenException e) {
            // 處理TokenException  
            return R.error("Token驗證失敗: " + e.getMessage());
        } catch (Exception e) {
            // 處理其他異常  
            return R.error("發(fā)生未知錯誤: " + e.getMessage());
        }
    }
}
// TokenException類,用于處理與Token相關(guān)的異常  
public class TokenException extends Exception {  
    public TokenException(String message) {  
        super(message);  
    }  
}  
}

R結(jié)果集

創(chuàng)建一個R結(jié)果集用來封裝結(jié)果

//統(tǒng)一返回為結(jié)果集R   1為成功,0為失敗
public class R<T>  {

    private Integer code; //編碼:1成功,0和其它數(shù)字為失敗
    private String msg; //錯誤信息
    private T data; //數(shù)據(jù)

    //靜態(tài)方法返回成功時候,R的屬性
    public static <T> R<T> success(T object) {
        R<T> r = new R<>();
        r.data = object;
        r.code = 1;
        return r;
    }

    //靜態(tài)方法返回失敗時傳入消息
    public static <T> R error(String msg) {
        R r = new R();
        r.msg = msg;
        r.code = 0;
        return r;
    }
    // getter和setter方法省略...  
}

返回一個生成的token

在用戶發(fā)送登錄請求后如果驗證通過就返回一個生成的token

 String token=JwtTokenUtil.createToken(String.valueOf(user.getId()),3600000L);//生成token返回前端
 return R.success(token);

接下來就是攔截所有請求并且驗證響應(yīng)頭的token是否正確

  • 請求頭的格式通常為:Authorization: Bearer JWT

線程工具類

在每次請求時在當(dāng)前線程進行存儲信息

public class BaseContext {
    // 使用ThreadLocal來存儲用戶ID
    private static final ThreadLocal<String> userIdThreadLocal = new ThreadLocal<>();

    // 設(shè)置用戶ID
    public static void setUserId(String userId) {
        userIdThreadLocal.set(userId);
    }

    // 獲取用戶ID
    public static String getUserId() {
        return userIdThreadLocal.get();
    }

    // 清除用戶ID(通常在請求處理完畢后調(diào)用)
    public static void clearUserId() {
        userIdThreadLocal.remove();
    }
}

創(chuàng)建攔截器

import com.certificateManage.common.BaseContext;
import com.certificateManage.common.R;
import com.certificateManage.util.tokenUtil.JwtTokenUtil;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class JwtInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 從請求頭中獲取JWT
        String token = request.getHeader("Authorization");
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())){
            System.out.println("OPTIONS請求,放行");
            return true;
        }
        if (token == null || !token.startsWith("Bearer ")) {
            // 如果沒有JWT或者格式不正確,返回錯誤
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "token令牌不存在或請求頭格式錯誤");
            return false;
        }
        // 去除"Bearer "前綴,獲取真正的JWT
        token = token.substring(7);

        try {
            // 驗證JWT
            R r=JwtTokenUtil.checkToken(token);
            // JWT驗證成功,繼續(xù)處理請求
            if (r.getCode()==1) {
                // 將用戶ID存儲在ThreadLocal中
                BaseContext.setUserId(String.valueOf(r.getData()));
                return true;
            }else {
                // JWT驗證失敗,返回錯誤
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token驗證失敗");
                return false;
            }
        } catch (Exception e) {
            // JWT驗證失敗,返回錯誤
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token驗證失敗");
            return false;
        }
    }

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

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 在請求處理完畢后清除用戶ID
        BaseContext.clearUserId();
    }
}

這樣就可以在每次請求驗證Token,并把token中存儲的用戶id存到當(dāng)前線程.方便我們對發(fā)送請求的用戶進行操作

總結(jié)

到此這篇關(guān)于SpringBoot整合JWT(JSON Web Token)生成token與驗證的文章就介紹到這了,更多相關(guān)SpringBoot整合JWT生成token與驗證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringMVC上傳文件的三種實現(xiàn)方式

    SpringMVC上傳文件的三種實現(xiàn)方式

    本篇文章主要介紹了SpringMVC上傳文件的三種實現(xiàn)方式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • java外部類與內(nèi)部類簡介

    java外部類與內(nèi)部類簡介

    這篇文章簡單介紹了java外部類與內(nèi)部類,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • 簡單剖析Java中動態(tài)線程池的擴容以及縮容操作

    簡單剖析Java中動態(tài)線程池的擴容以及縮容操作

    這篇文章主要為大家詳細(xì)介紹了Java中動態(tài)線程池的擴容以及縮容操作的相關(guān)知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-01-01
  • Java創(chuàng)建數(shù)組的幾種方式總結(jié)

    Java創(chuàng)建數(shù)組的幾種方式總結(jié)

    下面小編就為大家?guī)硪黄狫ava創(chuàng)建數(shù)組的幾種方式總結(jié)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-10-10
  • 詳解Java高階語法Volatile

    詳解Java高階語法Volatile

    這篇文章主要介紹了Java高階語法Volatile,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • 教你如何測試Spring Data JPA的Repository

    教你如何測試Spring Data JPA的Repository

    Spring Data JPA 提供了一些便捷的方式來測試這種持久層的代碼,常見的兩種測試類型是集成測試和單元測試,本文通過示例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • Java 注解的使用實例詳解

    Java 注解的使用實例詳解

    這篇文章主要介紹了Java 注解的使用實例詳解的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • Java中的Lock與ReentrantLock深入解析

    Java中的Lock與ReentrantLock深入解析

    這篇文章主要介紹了Java中的Lock與ReentrantLock深入解析,Lock位于java.util.concurrent.locks包下,是一種線程同步機制,就像synchronized塊一樣,但是,Lock比synchronized塊更靈活、更復(fù)雜,需要的朋友可以參考下
    2024-01-01
  • JAVA破壞單例模式的方式以及避免方法

    JAVA破壞單例模式的方式以及避免方法

    這篇文章主要介紹了JAVA破壞單例模式的方式以及避免方法,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • Spring注解驅(qū)動之ApplicationListener異步處理事件說明

    Spring注解驅(qū)動之ApplicationListener異步處理事件說明

    這篇文章主要介紹了Spring注解驅(qū)動之ApplicationListener異步處理事件說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-09-09

最新評論

海城市| 儋州市| 神池县| 苍梧县| 新绛县| 赣州市| 花垣县| 水富县| 黄大仙区| 安龙县| 上林县| 田林县| 白山市| 大渡口区| 黑水县| 金寨县| 普格县| 称多县| 沂南县| 荃湾区| 黑河市| 南部县| 河北省| 桦南县| 新干县| 青岛市| 甘南县| 信阳市| 綦江县| 九江市| 康定县| 泗阳县| 中牟县| 兴山县| 潢川县| 漳州市| 松原市| 洱源县| 凭祥市| 嘉义市| 新丰县|