說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 結合上一篇文章使用,味道更佳:從0到1 ...
說明
該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。
該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。
說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。
結合上一篇文章使用,味道更佳:從0到1搭建許可權管理系統系列二 .net8 使用JWT鑒權(附當前源碼)
有興趣的朋友,請關註我吧(*^▽^*)。
關註我,學不會你來打我
創建Token
創建token的因素(條件)有很多,在該篇文章中,採用jwt配置和用戶基本信息作為生成token的基本因素(讀者可根據系統,自由改變生成token因素)。
在JwtPlugInUnit.CS中創建2個方法(JwtPlugInUnit.CS在上一篇文章中有寫到)
方法一:PropValuesType方法
/// <summary> /// 反射獲取欄位 /// </summary> /// <param name="obj"></param> /// <returns></returns> public static IEnumerable<(string Name, object Value, string Type)> PropValuesType(this object obj) { List<(string a, object b, string c)> result = new List<(string a, object b, string c)>(); var type = obj.GetType(); var props = type.GetProperties(); foreach (var item in props) { result.Add((item.Name, item.GetValue(obj), item.PropertyType.Name)); } return result; }
上述方法:PropValuesType是通過反射獲取模型欄位和屬性。在本文章中,是為了提取登錄人員信息,編寫成List<Claim>,組成生成token的因素之一。
方法二:BuildToken方法
/// <summary> /// 生成Token /// </summary> /// <param name="loginResult">登陸返回信息</param> /// <returns></returns> public static LoginOutPut BuildToken(LoginInput loginResult) { LoginOutPut result = new LoginOutPut(); //獲取配置 var jwtsetting = AppSettingsPlugInUnit.GetNode<JwtSettingModel>("JwtSetting"); //準備calims,記錄登錄信息 var calims = loginResult.PropValuesType().Select(x => new Claim(x.Name, x.Value.ToString(), x.Type)).ToList(); //創建header var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtsetting.SecurityKey)); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var header = new JwtHeader(creds); //創建payload var payload = new JwtPayload(jwtsetting.Issuer, jwtsetting.Audience, calims, DateTime.Now, DateTime.Now.AddMinutes(jwtsetting.ExpireSeconds)); //創建令牌 var token = new JwtSecurityToken(header, payload); var tokenStr = new JwtSecurityTokenHandler().WriteToken(token); result.ExpiresDate = token.ValidTo.AddHours(8).ToString(); result.Token = tokenStr; result.UserName = loginResult.UserName; return result; }
上述方法:BuildToken是創建token的核心代碼,它通過用戶信息+jwt配置信息生成token,並返回token、用戶名、token過期時間等信息(讀者可以添加更多返回信息)。
BuildToken中有2個模型,具體結構和位置如下:
創建Model類,用於存放系統中模型。
LoginInput模型結構如下:
/// <summary> /// 登錄輸入模型 /// </summary> public class LoginInput { /// <summary> /// 用戶名 /// </summary> public string? UserName { get; set; } /// <summary> /// 密碼 /// </summary> public string? Password { get; set; } }
LoginOutPut模型結構如下:
/// <summary> /// 登錄輸入模型 /// </summary> public class LoginOutPut { /// <summary> /// 用戶名 /// </summary> public string? UserName { get; set; } /// <summary> /// 密碼 /// </summary> public string? Password { get; set; } /// <summary> /// Token /// </summary> public string? Token { get; set; } /// <summary> /// Token過期時間 /// </summary> public string? ExpiresDate { get; set; } }
做完以上操作,用戶就可以生成Token,但要把token運用到系統中,還需做以下操作。
創建模塊分組
在ModeuleGroupEnum.cs中創建2個枚舉,具體如下
說明:ModeuleGroupEnum.cs在從0到1搭建許可權管理系統系列一 .net8 使用Swagger(附當前源碼) 文章中有說明(或者關註我的微信公眾號)。
/// <summary> /// 模塊分組 /// </summary> public enum ModeuleGroupEnum { /// <summary> /// 系統菜單 /// </summary> SysMenu = 1, /// <summary> /// 系統用戶 /// </summary> SysUser = 2, /// <summary> /// 基礎 /// </summary> Base = 3, }
新增【系統用戶】、【基礎】2個枚舉。
創建新控制器
創建2個控制器:BaseController和SysUserController,結構如下
創建BaseController基礎控制器,它存在的作用,就是承擔系統中需要重寫方法和獲取用戶基本信息的橋梁。
代碼如下:
/// <summary> /// 系統基礎模塊 /// </summary> [ApiController] [Route("api/[controller]/[action]")] [ApiExplorerSettings(GroupName = nameof(ModeuleGroupEnum.Base))] [Authorize] public class BaseController : ControllerBase { /// <summary> /// 獲取登陸人員信息 /// </summary> /// <returns></returns> [HttpGet] public LoginOutPut GetLoginUserMsg() { StringValues s = new StringValues(); var auth = Request.Headers.TryGetValue("Authorization", out s); if (string.IsNullOrWhiteSpace(s)) throw new Exception("登錄信息失效"); var token = new JwtSecurityTokenHandler().ReadJwtToken(s.ToString().Replace($"{JwtBearerDefaults.AuthenticationScheme} ", "")); LoginOutPut loginResult = new() { UserName = token.Claims.FirstOrDefault(f => f.Type == "UserName").Value, Password = Convert.ToString(token.Claims.FirstOrDefault(f => f.Type == "Password").Value), }; return loginResult; } }
解讀下該方法:通過獲取Headers中的Token,然後使用jwt反解析token獲取在BuildToken方法中記錄的用戶基本信息。
說明:控制器上方存在[Authorize],只要有控制器繼承基礎控制【BaseController】,那麼該控制器下的所有方法,都需要經過jwt驗證。如果某一個介面不需要token驗證,就在該介面上方添加 [AllowAnonymous]
創建SysUserController控制器,並繼承BaseController控制器,它的作用就是承擔系統用戶的所有介面,具體代碼如下:
/// <summary> /// 用戶模塊 /// </summary> [ApiController] [Route("api/[controller]/[action]")] [ApiExplorerSettings(GroupName = nameof(ModeuleGroupEnum.SysUser))] public class SysUserController : BaseController { /// <summary> /// 獲取Token /// </summary> /// <param name="userName">用戶名</param> /// <param name="password">密碼</param> [HttpGet] [AllowAnonymous] public string GetToken(string userName, string password) { var loginResult = JwtPlugInUnit.BuildToken(new LoginInput { UserName = userName, Password = password }); return loginResult.Token ?? string.Empty; } }
可以看到,該控制器下有2個介面,一個為獲取token介面(可同時作為登錄介面),一個為獲取登錄人員信息的介面(繼承BaseController下的GetLoginUserMsg()方法)。
做完以上操作,jwt中token驗證就完成啦,看一下成果。
不使用token訪問介面,不會成功
先獲取token
在添加使用token
點擊Authorize確定使用
再次訪問GetLoginUserMsg()介面,看下效果
回覆評論
上一篇文章:從0到1搭建許可權管理系統系列二 .net8 使用JWT鑒權(附當前源碼)得到了較多評論,有指正的、有疑問的。
首先感謝大家的閱讀,感謝大家的指正,也感謝大家的提問。
在這裡我針對些問題,回覆如下:
回覆一:
確實,在.net core 剛發佈的時候,所有人在微軟的引導下都對這一門的開源的框架,大家都叫它.net core ,它的出現也讓c#在生死的邊緣,獲得一線生機。但在.net core 3.1(應該)之後,就改名叫.net5 .net8等。
回覆二:
jwt它是輕量級的庫,所有它在這方面的處理,並不是很好。所以建議新增中間件驗證過期token或者把Token存到資料庫或緩存中,以此來操作複雜的鑒權驗證。
回覆三:
艾特這2位朋友,你要的來了,順便求關註博客園、關註微信公眾號,不錯過每次更新。
感謝你的耐心觀看。
如果對你有幫助,請關註我微信公眾號吧(*^▽^*)。
源代碼地址:https://gitee.com/yangguangchenjie/overall-auth2.0-web-api
幫我Star,謝謝。
有興趣的朋友,請關註我微信公眾號吧(*^▽^*)。
關註我:一個全棧多端的寶藏博主,定時分享技術文章,不定時分享開源項目。關註我,帶你認識不一樣的程式世界