處理JWT Token失效需求

JWT 本身是無狀態的,這意味著服務器不會保存任何關于 Token 的狀態信息。但為了支持 JWT 的狀態管理(例如:強制使某些 Token 失效),可以借助 Redis 這樣的外部存儲來維護一個黑名單或白名單。

  1. 安裝必要的 NuGet 包
    首先需要安裝以下 NuGet 包:
StackExchange.Redis;//用于與 Redis 數據庫交互。
Microsoft.AspNetCore.Authentication.JwtBearer;//用于處理 JWT 認證。
  1. 配置 Redis 連接
    在 appsettings.json 文件中添加 Redis 配置:
{"Redis": {"ConnectionString": "localhost:6379"}
}

3.創建 Redis 緩存服務
接口

 public interface IRedisCacheService{/// <summary>/// 設置redis/// </summary>/// <param name="key"></param>/// <param name="value"></param>/// <param name="expiry"></param>void Set(string key, string value, TimeSpan expiry);/// <summary>/// 刪除/// </summary>/// <param name="key"></param>void Remove(string key);/// <summary>/// 獲取/// </summary>/// <param name="key"></param>/// <returns></returns>string Get(string key);/// <summary>/// 判斷是否存在/// </summary>/// <param name="key"></param>/// <returns></returns>bool Exists(string key);}

實現類

 public class RedisCacheService : IRedisCacheService{private readonly IDatabase _redisDb;public RedisCacheService(IConnectionMultiplexer redis){_redisDb = redis.GetDatabase();}public void Set(string key, string value, TimeSpan expiry){_redisDb.StringSet(key, value, expiry);}public void Remove(string key){_redisDb.KeyDelete(key);}public string Get(string key){return _redisDb.StringGet(key);}public bool Exists(string key){return _redisDb.KeyExists(key);}}

自定義一個擴展類

 public static IServiceCollection AddRedisCacheService(this IServiceCollection services){return services.AddSingleton<IRedisCacheService, RedisCacheService>();}
  1. 注冊依賴注入服務
    在Program.cs注冊服務
在這里插入代碼片builder.Services.AddControllers(opt =>{opt.Filters.Add<Filter.JWTAuthorizationFilter>(); // 添加 JWT 授權過濾器});// 配置 Redis服務 builder.Services.Configure<RedisSetting>(builder.Configuration.GetSection("RedisConnection")); // 注入 Redis 配置var redisSetting = builder.Configuration.GetSection("RedisConnection").Get<RedisSetting>();builder.Services.AddSingleton<IConnectionMultiplexer>(ConnectionMultiplexer.Connect(redisSetting.ConnectionString));
builder.Services.AddRedisCacheService();// 創建個DTO保存redis配置public class RedisSetting{public string ConnectionString { get; set; }}
  1. 登錄時保存Redis信息
    a.登錄成功后,將用戶的 JWTVersion 寫入 Redis。每次登錄版本號不一致,可以解決跨瀏覽器登錄和跨地區登錄。
    b.如果登錄人狀態被禁用了,重新設置下Redis的值即可。
 /// <summary>/// 登錄/// </summary>/// <param name="login"></param>/// <returns></returns>[HttpPost][NoAuthAttribute]public async Task<IActionResult> Login([FromBody] LoginModel login){var user = await _userManager.FindByNameAsync(login.UserName);if (user == null){return new JsonResult(new { Code = 400, Message = "用戶不存在" });}if (!await _userManager.CheckPasswordAsync(user, login.Password)){return new JsonResult(new { Code = 400, Message = "密碼錯誤" });}var guid = Guid.NewGuid().ToString();var redisKey = $"{user.Id}_user.Id";var roles = await _userManager.GetRolesAsync(user);var token = _jwtService.GenerateToken(user.Id, user.UserName, guid, roles.ToList());// 設置redis和redis1小時過期_redisDb.Set(redisKey, guid, TimeSpan.FromHours(1));return new JsonResult(new { Code = 200, Message = "登錄成功", Token = token });}
// 使用自定義注解,去掉登錄時的過濾攔截public class NoAuthAttribute : Attribute{}
  1. 使用過濾器來過濾請求中的數據是否有效
public class JWTAuthorizationFilter : IAsyncActionFilter
{private readonly UserManager<MyUser> userManager;private readonly IRedisCacheService redisDb;public JWTAuthorizationFilter(UserManager<MyUser> userManager, IRedisCacheService redisCache){this.userManager = userManager;this.redisDb = redisCache;}public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next){// 排除掉登錄不需要校驗的問題var controllerAttr = context.Controller.GetType().GetCustomAttributes(typeof(NoAuthAttribute), true).Any();if (controllerAttr){await next();return;}var haveNoAuth = context.ActionDescriptor.EndpointMetadata.Any(p => p is NoAuthAttribute || p is AllowAnonymousAttribute);if (haveNoAuth){await next();return;}// 這里可以添加 JWT 驗證邏輯// 如果驗證失敗,可以返回 401// 如果驗證成功,繼續執行下一個操作if (!context.HttpContext.Request.Headers.TryGetValue("Authorization", out var token)){context.Result = new ObjectResult("請求頭,沒有Authorization參數") { StatusCode = 401 };return;}token = token.ToString().Replace("Bearer ", "");if (string.IsNullOrEmpty(token)){context.Result = new ObjectResult("請求頭,token為空") { StatusCode = 401 };return;}var jwtVersion = context.HttpContext.User.FindFirstValue("JWTVersion");var userId = context.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);if (string.IsNullOrEmpty(jwtVersion) || string.IsNullOrEmpty(userId)){context.Result = new ObjectResult("JWTVersion或NameIdentifier為空") { StatusCode = 401 };return;}var redisKey = $"{userId}_user.Id";var sourceGuid = redisDb.Get(redisKey);// 判斷當前的版本號是否一致,不一致校驗token失效if (string.IsNullOrEmpty(sourceGuid) || sourceGuid != jwtVersion){context.Result = new ObjectResult("token已失效") { StatusCode = 401 };return;}await next();}
}

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

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

相關文章

PHP代碼審計-01

&#x1f338; 連接方式 PHP Mysql連接方式&#xff1a; Mysql&#xff08;廢棄&#xff09;MysqliPDO &#x1f338; 常見過濾 intval/addslashes/mysql_real_escape mysqli_escape_string/mysqli_real_escape_string/mysqli::escape_string PDO::quote 參數化查詢 a…

SpringKafka錯誤處理:重試機制與死信隊列

文章目錄 引言一、Spring Kafka錯誤處理基礎二、配置重試機制三、死信隊列實現四、特定異常的處理策略五、整合事務與錯誤處理總結 引言 在構建基于Kafka的消息系統時&#xff0c;錯誤處理是確保系統可靠性和穩定性的關鍵因素。即使設計再完善的系統&#xff0c;在運行過程中也…

藍橋杯2024JavaB組的一道真題的解析

文章目錄 1.問題描述2.問題描述3.思路分析4.代碼分析 1.問題描述 這個是我很久之前寫的一個題目&#xff0c;當時研究了這個題目好久&#xff0c;發布了一篇題解&#xff0c;后來很多人點贊&#xff0c;我都沒有意識到這個問題的嚴重性&#xff0c;我甚至都在懷疑自己&#xf…

性能比拼: Go標準庫 vs Python FastAPI(第二輪)

本內容是對知名性能評測博主 Anton Putra Python (FastAPI) vs Go (Golang) (Round 2) Performance Benchmark 內容的翻譯與整理, 有適當刪減, 相關指標和結論以原作為準 介紹 這是第二輪關于 FastAPI 和 Golang 的對比測試。我幾天前運行了前一次的基準測試&#xff0c;到目…

DeepSeek與ChatGPT的優勢對比:選擇合適的工具來提升工作效率

選DeepSeek還是ChatGPT&#xff1f;這就像問火鍋和披薩哪個香&#xff01; "到底該用DeepSeek還是ChatGPT?” 這個問題最近在互聯網圈吵翻天!其實這就跟選手機系統-樣&#xff0c;安卓黨iOS黨都能說出一萬條理由&#xff0c;但真正重要的是你拿它來干啥&#xff01;&am…

Python爬蟲第4節-請求庫urllib的request模塊使用

目錄 前言&#xff1a;基本庫urllib的使用 一、urlopen方法 二、Request類 三、高級用法 前言&#xff1a;基本庫urllib的使用 開始學習爬蟲時&#xff0c;第一步就是要模擬瀏覽器給服務器發送請求。這個時候&#xff0c;你可能會有很多問題&#xff1a;該從哪里開始做呢&a…

Vue3 Pinia Store使用示例

代碼示例&#xff1a; import { defineStore } from "pinia"; // 導入 Pinia 的 defineStore 方法 import { ref } from "vue"; // 導入 Vue 的響應式 API ref import { type Menu } from "/interface"; // 導入自定義的 Menu 類型/…

JavaScript逆向魔法:Chrome開發者工具探秘之旅

在前端開發和安全研究領域&#xff0c;JavaScript逆向工程是一項關鍵技能。它涉及分析和理解代碼的執行流程、數據結構和邏輯&#xff0c;以發現潛在的安全漏洞、提取核心算法或實現功能兼容。本文將結合Chrome開發者工具的調試功能&#xff0c;并通過具體示例幫助你更好地理解…

Qt基礎:資源文件

資源文件 1. 資源文件2. 資源文件創建 1. 資源文件 資源文件顧名思義就是一個存儲資源的文件&#xff0c;在Qt中引入資源文件好處在于他能提高應用程序的部署效率并且減少一些錯誤的發生。 在程序編譯過程中&#xff0c; 添加到資源文件中的文件也會以二進制的形式被打包到可執…

Agent TARS與Manus的正面競爭

Agent TARS 是 Manus 的直接競爭對手&#xff0c;兩者在 AI Agent 領域形成了顯著的技術與生態對抗。 一、技術架構與功能定位的競爭 集成化架構 vs 模塊化設計 Agent TARS 基于字節跳動的 UI-TARS 視覺語言模型&#xff0c;將視覺感知、推理、接地&#xff08;grounding&#…

使用ssh連接上開發板

最后我發現了問題&#xff0c;我忘記指定用戶名了&#xff0c;在mobaXterm上左上角打開會話&#xff0c;點擊ssh&#xff0c;然后輸入要連接的開發板主機的ip地址&#xff0c;關鍵在這里&#xff0c;要指定你要連接的開發板的系統中存在的用戶&#xff0c;因為通過ssh連接一個設…

【性能優化點滴】odygrd/quill在編譯期做了哪些優化

Quill 是一個高性能的 C 日志庫&#xff0c;它在編譯器層面進行了大量優化以確保極低的運行時開銷。以下是 Quill 在編譯器優化方面的關鍵技術和實現細節&#xff1a; 1. 編譯時字符串解析與格式校驗 Quill 在編譯時完成格式字符串的解析和校驗&#xff0c;避免運行時開銷&…

【數據結構】排序算法(中篇)·處理大數據的精妙

前引&#xff1a;在進入本篇文章之前&#xff0c;我們經常在使用某個應用時&#xff0c;會出現【商品名稱、最受歡迎、購買量】等等這些榜單&#xff0c;這里面就運用了我們的排序算法&#xff0c;作為剛學習數據結構的初學者&#xff0c;小編為各位完善了以下幾種排序算法&…

混雜模式(Promiscuous Mode)與 Trunk 端口的區別詳解

一、混雜模式&#xff08;Promiscuous Mode&#xff09; 1. 定義與工作原理 定義&#xff1a;混雜模式是網絡接口的一種工作模式&#xff0c;允許接口接收通過其物理鏈路的所有數據包&#xff0c;而不僅是目標地址為本機的數據包。工作層級&#xff1a;OSI 數據鏈路層&#x…

大學生機器人比賽實戰(一)綜述篇

大學生機器人比賽實戰 參加機器人比賽是大學生提升工程實踐能力的絕佳機會。本指南將全面介紹如何從零開始準備華北五省機器人大賽、ROBOCAN、RoboMaster等主流機器人賽事&#xff0c;涵蓋硬件設計、軟件開發、算法實現和團隊協作等關鍵知識。 一、比賽選擇與準備策略 1.1 主…

【Linux】動靜態庫知識大梳理

親愛的讀者朋友們&#x1f603;&#xff0c;此文開啟知識盛宴與思想碰撞&#x1f389;。 快來參與討論&#x1f4ac;&#xff0c;點贊&#x1f44d;、收藏?、分享&#x1f4e4;&#xff0c;共創活力社區。 在 Linux 系統編程中&#xff0c;動靜態庫是重要的組成部分&#xff0…

06-公寓租賃項目-后臺管理-公寓管理篇

尚庭公寓項目/公寓管理模塊 https://www.yuque.com/pkqzyh/qg2yge/5ba67653b51379d18df61b9c14c3e946 一、屬性管理 屬性管理頁面包含公寓和房間各種可選的屬性信息&#xff0c;其中包括房間的可選支付方式、房間的可選租期、房間的配套、公寓的配套等等。其所需接口如下 1.1…

Links for llama-cpp-python whl安裝包下載地址

Links for llama-cpp-python whl安裝包下載地址 Links for llama-cpp-python whl安裝包下載地址 https://github.com/abetlen/llama-cpp-python/releases

為境外組織提供企業商業秘密犯法嗎?

企業商業秘密百問百答之九十六&#xff1a;為境外組織提供企業商業秘密犯法嗎&#xff1f; 在日常的對外交流中&#xff0c;企業若暗中為境外的機構、組織或人員竊取、刺探、收買或非法提供商業秘密&#xff0c;這種行為嚴重侵犯了商業秘密權利人的合法權益&#xff0c;更深遠…

grep 命令詳解(通俗版)

1. 基礎概念 grep 是 Linux 下的文本搜索工具&#xff0c;核心功能是從文件或輸入流中篩選出包含指定關鍵詞的行。 它像“文本界的搜索引擎”&#xff0c;能快速定位關鍵信息&#xff0c;特別適合日志分析、代碼排查等場景。 2. 基礎語法 grep [選項] "搜索詞" 文件…