JWT令牌驗證

一、JWT 驗證方式詳解

JWT(JSON Web Token)的驗證核心是確保令牌未被篡改符合業務規則,主要分為以下步驟:

1. 令牌解析與基礎校驗

收到客戶端傳遞的 JWT 后,首先按 . 分割為三部分:HeaderPayloadSignature

  • Header:解析算法(如 HS256)和令牌類型(固定為 JWT)。
  • Payload:解析標準聲明(如 exp 過期時間、iat 簽發時間)和自定義聲明(如用戶 ID)。
2. 簽名驗證(防篡改)

簽名是 JWT 的核心安全屏障。驗證邏輯:

  • 使用 Header 中指定的算法(如 HMAC SHA256),用服務端保存的密鑰Header.Base64UrlEncode() + "." + Payload.Base64UrlEncode() 重新計算簽名。
  • 對比新計算的簽名與 JWT 中的 Signature,若不一致則令牌無效(可能被篡改)。
3. 聲明校驗(業務規則)

驗證 Payload 中的聲明是否符合業務要求:

  • exp(Expiration Time):令牌過期時間戳,需滿足 當前時間 < exp(考慮時鐘偏差,如 ±300秒)。
  • iat(Issued At):令牌簽發時間,需滿足 iat ≤ 當前時間
  • iss(Issuer):令牌簽發者,需與服務端配置的簽發者(如 https://your-domain.com)一致。
  • aud(Audience):令牌接收方,需與當前服務身份(如 user-service)匹配。
  • 自定義聲明:如用戶角色(role)、權限(permissions)等,按業務需求驗證。
4. 令牌狀態校驗(可選)

對于需要主動失效的令牌(如用戶注銷),需維護一個黑名單(如 Redis),驗證時檢查令牌是否在黑名單中(適用于需要嚴格控制令牌生命周期的場景)。


二、后端 Java 示例(Spring Boot + JJWT)

以下是基于 Spring Boot 的 JWT 生成與驗證接口實現,使用 JJWT 庫(Java JWT 工具)。

1. 依賴配置

pom.xml 中添加 JJWT 依賴:

<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.11.5</version>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.11.5</version><scope>runtime</scope>
</dependency>
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.11.5</version><scope>runtime</scope>
</dependency>
2. JWT 工具類(核心邏輯)
import io.jsonwebtoken.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;@Component
public class JwtUtils {// 從配置文件讀取密鑰和過期時間(示例:密鑰為 "your-256-bit-secret",過期時間 30分鐘)@Value("${jwt.secret}")private String secret;@Value("${jwt.expire}")private long expire;// 生成 JWTpublic String generateToken(String userId) {Date now = new Date();Date expireDate = new Date(now.getTime() + expire * 1000); // 轉換為毫秒Map<String, Object> claims = new HashMap<>();claims.put("userId", userId); // 自定義聲明claims.put("role", "user");   // 自定義角色return Jwts.builder().setClaims(claims)          // 自定義聲明.setIssuer("your-domain")   // 簽發者(iss).setIssuedAt(now)           // 簽發時間(iat).setExpiration(expireDate)  // 過期時間(exp).signWith(SignatureAlgorithm.HS256, secret) // 簽名算法+密鑰.compact();}// 驗證 JWT 并解析聲明public Claims validateToken(String token) {try {return Jwts.parser().setSigningKey(secret)    // 使用相同密鑰驗證.parseClaimsJws(token)    // 解析 JWT.getBody();} catch (ExpiredJwtException e) {throw new RuntimeException("令牌已過期");} catch (UnsupportedJwtException e) {throw new RuntimeException("不支持的令牌類型");} catch (MalformedJwtException e) {throw new RuntimeException("令牌格式錯誤");} catch (SignatureException e) {throw new RuntimeException("簽名驗證失敗(可能被篡改)");} catch (IllegalArgumentException e) {throw new RuntimeException("令牌為空");}}
}
3. 接口示例(生成與驗證)
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;@RestController
@RequestMapping("/auth")
public class AuthController {@Resourceprivate JwtUtils jwtUtils;// 模擬登錄接口:返回 JWT@PostMapping("/login")public String login(@RequestParam String username, @RequestParam String password) {// 實際業務中需校驗用戶名密碼(示例直接通過)return jwtUtils.generateToken("123"); // 用戶 ID 為 123}// 驗證令牌接口(示例)@PostMapping("/validate")public String validate(@RequestHeader("Authorization") String token) {// 提取 Bearer 令牌(去掉 "Bearer " 前綴)String actualToken = token.replace("Bearer ", "");try {Claims claims = jwtUtils.validateToken(actualToken);return "驗證成功!用戶 ID:" + claims.get("userId");} catch (Exception e) {return "驗證失敗:" + e.getMessage();}}
}

三、前端/客戶端示例(Uniapp、WPF、Qt)

以下示例演示客戶端如何攜帶 JWT 調用后端驗證接口(假設后端地址為 http://localhost:8080)。

1. Uniapp(Vue 跨端框架)
<template><view><button @click="login">登錄獲取 Token</button><button @click="validateToken">驗證 Token</button><text>{{ result }}</text></view>
</template><script>
export default {data() {return {token: null,result: ""};},methods: {// 登錄獲取 Tokenasync login() {const res = await uni.request({url: "http://localhost:8080/auth/login",method: "POST",data: { username: "test", password: "123" }});this.token = res.data;this.result = "Token 獲取成功:" + this.token;},// 驗證 Token(攜帶到請求頭)async validateToken() {if (!this.token) {this.result = "請先登錄獲取 Token";return;}const res = await uni.request({url: "http://localhost:8080/auth/validate",method: "POST",header: { Authorization: `Bearer ${this.token}` }});this.result = res.data;}}
};
</script>
2. WPF(.NET 桌面應用)
using System;
using System.Net.Http;
using System.Windows;namespace WpfJwtDemo {public partial class MainWindow : Window {private string _token;private readonly HttpClient _httpClient = new HttpClient();public MainWindow() {InitializeComponent();_httpClient.BaseAddress = new Uri("http://localhost:8080/");}// 登錄獲取 Tokenprivate async void LoginButton_Click(object sender, RoutedEventArgs e) {var formData = new FormUrlEncodedContent(new[] {new KeyValuePair<string, string>("username", "test"),new KeyValuePair<string, string>("password", "123")});var response = await _httpClient.PostAsync("auth/login", formData);_token = await response.Content.ReadAsStringAsync();ResultText.Text = "Token獲取成功:" + _token;}// 驗證 Token(攜帶到請求頭)private async void ValidateButton_Click(object sender, RoutedEventArgs e) {if (string.IsNullOrEmpty(_token)) {ResultText.Text = "請先登錄獲取 Token";return;}_httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _token);var response = await _httpClient.PostAsync("auth/validate", null);var result = await response.Content.ReadAsStringAsync();ResultText.Text = result;}}
}
3. Qt(C++ 跨平臺框架)
#include <QApplication>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrlQuery>
#include <QMessageBox>class JwtDemo : public QObject {Q_OBJECT
public:JwtDemo(QObject *parent = nullptr) : QObject(parent) {manager = new QNetworkAccessManager(this);connect(manager, &QNetworkAccessManager::finished, this, &JwtDemo::onRequestFinished);}// 登錄獲取 Tokenvoid login() {QUrl url("http://localhost:8080/auth/login");QUrlQuery query;query.addQueryItem("username", "test");query.addQueryItem("password", "123");QNetworkRequest request(url);request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");manager->post(request, query.toString(QUrl::FullyEncoded).toUtf8());}// 驗證 Token(攜帶到請求頭)void validateToken(const QString &token) {QUrl url("http://localhost:8080/auth/validate");QNetworkRequest request(url);request.setRawHeader("Authorization", "Bearer " + token.toUtf8());manager->post(request, ""); // 空 body}private slots:void onRequestFinished(QNetworkReply *reply) {if (reply->error() == QNetworkReply::NoError) {QString result = reply->readAll();if (reply->url().path() == "/auth/login") {currentToken = result;QMessageBox::information(nullptr, "成功", "Token獲取成功:" + result);} else if (reply->url().path() == "/auth/validate") {QMessageBox::information(nullptr, "驗證結果", result);}} else {QMessageBox::critical(nullptr, "錯誤", "請求失敗:" + reply->errorString());}reply->deleteLater();}private:QNetworkAccessManager *manager;QString currentToken;
};int main(int argc, char *argv[]) {QApplication app(argc, argv);JwtDemo demo;// 模擬點擊登錄(實際需綁定UI事件)demo.login();// 假設登錄后驗證(實際需等待登錄完成)QTimer::singleShot(2000, [&demo]() {if (!demo.currentToken.isEmpty()) {demo.validateToken(demo.currentToken);}});return app.exec();
}#include "main.moc" // 需包含 moc 文件(Qt 元對象編譯)

四、關鍵說明

  1. 密鑰安全:后端密鑰(jwt.secret)需嚴格保密,避免硬編碼在代碼中(建議通過配置中心或環境變量獲取)。
  2. 過期時間exp 需根據業務場景設置(如用戶登錄態建議 30分鐘~1天,敏感操作建議更短)。
  3. 客戶端處理:前端需將 JWT 存儲在 localStorage(Web)、SecureStorage(移動端)或 注冊表(桌面端)中,避免明文存儲。
  4. 跨域問題:若前端與后端不同域,需在后端配置 CORS(跨域資源共享)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/83899.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/83899.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/83899.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

一文講清python、anaconda的安裝以及pycharm創建工程

軟件下載 Pycharm下載地址&#xff1a; Other Versions - PyCharm anaconda下載地址&#xff1a; https://repo.anaconda.com/archive/Anaconda3-2024.06-1-Windows-x86_64.exe 安裝步驟 一、 Python 解釋器的安裝步驟 安裝目錄介紹&#xff1a; 二、 Anaconda 安裝 2.1 安裝步…

Mac如何允許安裝任何來源軟件?

打開系統偏好設置-安全性與隱私&#xff0c;點擊右下角的解鎖按鈕&#xff0c;選擇允許從任何來源。 如果沒有這一選項&#xff0c;請到打開終端&#xff0c;輸入命令行&#xff1a;sudo spctl --master-disable, 輸入命令后回車&#xff0c;輸入電腦的開機密碼后回車。 返回“…

React Flow 中 Minimap 與 Controls 組件使用指南:交互式小地圖與視口控制定制(含代碼示例)

本文為《React Agent&#xff1a;從零開始構建 AI 智能體》專欄系列文章。 專欄地址&#xff1a;https://blog.csdn.net/suiyingy/category_12933485.html。項目地址&#xff1a;https://gitee.com/fgai/react-agent&#xff08;含完整代碼示?例與實戰源&#xff09;。完整介紹…

Windows Ubuntu 目錄映射關系

情況一&#xff1a;你是通過 WSL (Windows Subsystem for Linux) 安裝 Ubuntu 這是最常見的情況。如果你在 Microsoft Store 安裝了 “Ubuntu”&#xff0c;默認就是 WSL。 &#x1f4c1; 目錄映射關系如下&#xff1a; 從 Ubuntu&#xff08;WSL&#xff09;訪問 Windows&…

雙指針法高效解決「移除元素」問題

雙指針法高效解決「移除元素」問題 雙指針法高效解決「移除元素」問題一、問題描述二、解法解析&#xff1a;雙指針法1. 核心思想2. 算法步驟3. 執行過程示例 三、關鍵點分析四、復雜度分析五、與其他解法的比較1. 快慢指針法2. 本解法的優勢 六、實際應用場景七、總結 雙指針法…

知識圖譜構架

目錄 知識圖譜構架 一、StanfordNLP 和 spaCy 工具介紹 &#xff08;一&#xff09;StanfordNLP 主要功能 使用示例 &#xff08;二&#xff09;spaCy 主要功能 使用示例 二、CRF 和 BERT 的基本原理和入門 &#xff08;一&#xff09;CRF&#xff08;條件隨機場&…

激光三角測量標定與應用

文章目錄 1&#xff0c;介紹。2&#xff0c;技術原理3&#xff0c;類型。3.1&#xff0c;直射式3.2&#xff0c;斜射式3.3&#xff0c;兩種三角位移傳感器特性的比較 4&#xff0c;什么是光片&#xff1f;5&#xff0c;主要的算子。1&#xff0c;create_sheet_of_light_model2&…

高可用消息隊列實戰:AWS SQS 在分布式系統中的核心解決方案

引言&#xff1a;消息隊列的“不可替代性” 在微服務架構和分布式系統盛行的今天&#xff0c;消息隊列&#xff08;Message Queue&#xff09; 已成為解決系統解耦、流量削峰、異步處理等難題的核心組件。然而&#xff0c;傳統的自建消息隊列&#xff08;如RabbitMQ、Kafka&am…

人工智能核心知識:AI Agent 的四種關鍵設計模式

人工智能核心知識&#xff1a;AI Agent 的四種關鍵設計模式 一、引言 在人工智能領域&#xff0c;AI Agent&#xff08;人工智能代理&#xff09;是實現智能行為和決策的核心實體。它能夠感知環境、做出決策并采取行動以完成特定任務。為了設計高效、靈活且適應性強的 AI Age…

平替BioLegend品牌-Elabscience PE Anti-Mouse Foxp3抗體:流式細胞術中的高效工具,助力免疫細胞分析!”

概述 調節性T細胞&#xff08;Treg&#xff09;在維持免疫耐受和抑制過度免疫反應中發揮關鍵作用&#xff0c;其標志性轉錄因子Foxp3&#xff08;Forkhead box P3&#xff09;是Treg功能研究的重要靶點。Elabscience 推出的抗小鼠Foxp3抗體&#xff08;3G3-E&#xff09;&…

編程日志5.13

鄰接表的基礎代碼 #include<iostream> using namespace std; //鄰接表的類聲明 class Graph {private: //結構體EdgeNode表示圖中的邊結點,包含頂點vertex、權重weight和指向下一個邊結點的指針next struct EdgeNode { int vertex; int weight; …

PowerBI 矩陣實現動態行內容(如前后銷售數據)統計數據,以及過濾同時為0的數據

我們有一張活動表 和 一張銷售表 我們想實現如下的效果&#xff0c;當選擇某個活動時&#xff0c;顯示活動前后3天的銷售對比圖&#xff0c;如下&#xff1a; 實現方法&#xff1a; 1.新建一個表&#xff0c;用于顯示列&#xff1a; 2.新建一個度量值&#xff0c;用SELECTEDVA…

Prompt Tuning:高效微調大模型的新利器

Prompt Tuning(提示調優)是什么 Prompt Tuning(提示調優) 是大模型參數高效微調(Parameter-Efficient Fine-Tuning, PEFT)的重要技術之一,其核心思想是通過優化 連續的提示向量(而非整個模型參數)來適配特定任務。以下是關于 Prompt Tuning 的詳細解析: 一、核心概念…

杰發科技AC7840——如何把結構體數據寫到Dflash中

1. 結構體數據被存放在Pflash中 正常情況下&#xff0c;可以看到全局變量的結構體數據被存放在Pflash中 數字部分存在RAM中 2. 最小編程單位 8字節編程&#xff0c;因此如果結構體存放在Dfalsh中&#xff0c;進行寫操作&#xff0c;需要寫8字節的倍數 第一種辦法&#xff1a;…

CSS 選擇器入門

一、CSS 選擇器基礎&#xff1a;快速掌握核心概念 什么是選擇器&#xff1f; CSS 選擇器就像 “網頁元素的遙控器”&#xff0c;用于定位 HTML 中的特定元素并應用樣式。 /* 結構&#xff1a;選擇器 { 屬性: 值; } */ p { color: red; } /* 選擇所有<p>元素&#xff0c;…

Anaconda3安裝教程(附加安裝包)Anaconda詳細安裝教程Anaconda3 最新版安裝教程

多環境隔離 可同時維護生產環境、開發環境、測試環境&#xff0c;例如&#xff1a; conda create -n ml python3.10 # 創建機器學習環境 conda activate ml # 激活環境三、Anaconda3 安裝教程 解壓Anaconda3安裝包 找到下載的 Anaconda3 安裝包&#xff08;.ex…

現代計算機圖形學Games101入門筆記(十七)

雙向路徑追蹤 外觀建模 散射介質 人的頭發不能用在動畫的毛發上。 動物的髓質Medulla特別大 雙層圓柱模型應用 BSSRDF是BRDF的延伸。 天鵝絨用BRDF不合理&#xff0c;轉成散射介質。 法線分布 光追很難處理微表面模型 光在微型細節上&#xff0c;光是一個波&#xff0c;會發生衍…

chrome源碼中WeakPtr 跨線程使用詳解:原理、風險與最佳實踐

base::WeakPtr 在 Chromium 中 不能安全地跨線程使用。這是一個很關鍵的點&#xff0c;下面詳細解釋原因及正確用法。 &#x1f50d;原理與使用 ? 先說答案&#xff1a; base::WeakPtr 本質上是**線程綁定&#xff08;thread-affine&#xff09;**的。不能在多個線程之間創建…

hysAnalyser 從MPEG-TS導出ES功能說明

摘要 hysAnalyser 是一款特色的 MPEG-TS 數據分析工具。本文主要介紹了 hysAnalyser 從MPEG-TS 中導出選定的 ES 或 PES 功能(版本v1.0.003)&#xff0c;以便用戶知悉和掌握這些功能&#xff0c;幫助分析和解決各種遇到ES或PES相關的實際問題。hysAnalyser 支持主流的MP1/MP2/…

C++(21):fstream的讀取和寫入

目錄 1 ios::out 2 ios::in和is_open 3 put()方法 4 get()方法 4.1 讀取單個字符 4.2 讀取多個字符 4.3 設置終結符 5 getline() 1 ios::out 打開文件用于寫入數據。如果文件不存在&#xff0c;則新建該文件&#xff1b;如果文件原來就存在&#xff0c;則打開時清除…