今天學習下JWT,遇到了兩個坑爹問題,這裡記錄下。在 ASP.NET Core 中,授權的設置方式有兩種,可以使用角色,也可以使用策略,這裡也將簡單舉例角色、策略的使用。 JWT這裡不做介紹,如果想瞭解更多,請看https://www.jianshu.com/p/a12fc67c9e05,https ...
今天學習下JWT,遇到了兩個坑爹問題,這裡記錄下。在 ASP.NET Core 中,授權的設置方式有兩種,可以使用角色,也可以使用策略,這裡也將簡單舉例角色、策略的使用。
JWT這裡不做介紹,如果想瞭解更多,請看https://www.jianshu.com/p/a12fc67c9e05,https://www.cnblogs.com/CreateMyself/p/11123023.html ,這兩篇都講解的很好,這裡只寫實際的使用和遇到的問題。
1. JWT的SecretKey必須16位以上
jwt中key必須16位以上,否則長度不夠會拋出異常,異常代碼如下
System.ArgumentOutOfRangeException HResult=0x80131502 Message=IDX10603: Decryption failed. Keys tried: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. Exceptions caught: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. token: '[PII is hidden. For more details, see https://aka.ms/IdentityModel/PII.]' Source=Microsoft.IdentityModel.Tokens StackTrace: at Microsoft.IdentityModel.Tokens.SymmetricSignatureProvider..ctor(SecurityKey key, String algorithm, Boolean willCreateSignatures) ....................
2.獲取token之後,一直401Unauthorized
在Startup.cs中的Configure中添加app.UseAuthentication();新創建.net core項目的時候,會自動添加授權app.UseAuthorization();但是JWT其實是一種認證,準確;來說是登錄的過程,需要用戶名和密碼的認證。
例如:你要登陸論壇,輸入用戶名張三,密碼1234,密碼正確,證明你張三確實是張三,這就是 認證authentication;那麼是否有刪除添加等的操作,這就是授權authorization
3.JWTtoken的獲取
//appsettings.json中增加配置信息 "JwtSettings": { "Issuer": "https://localhost:44378/", "Audience": "https://localhost:44378/", "SecretKey": "1234567890123456" }View Code
// Startup.cs中增加JWT的設置 services.AddAuthentication(options => { //認證middleware配置 options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(o => { //主要是jwt token參數設置 o.TokenValidationParameters = new TokenValidationParameters { //Token頒發機構 ValidIssuer = jwtSettings.Issuer, //頒發給誰 ValidAudience = jwtSettings.Audience, //這裡的key要進行加密,需要引用Microsoft.IdentityModel.Tokens IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey)), ValidateIssuerSigningKey = true, //是否驗證Token有效期,使用當前時間與Token的Claims中的NotBefore和Expires對比 ValidateLifetime = true, //允許的伺服器時間偏移量 ClockSkew = TimeSpan.Zero }; });View Code
// Controller中獲取token [HttpPost] public IActionResult Token(LoginModel login) { _logger.LogInformation($"獲取Token:User:{login.User}"); if (string.IsNullOrEmpty(login.User) || string.IsNullOrEmpty(login.Password))//判斷賬號密碼是否正確 { return BadRequest(); } var claim = new List<Claim>{ new Claim(ClaimTypes.Name,login.User), new Claim(ClaimTypes.Role,"Test") }; //建立增加策略的授權 if (login.User == "Test") claim.Add(new Claim("Test", "Test")); if (login.User == "Test1") claim.Add(new Claim("Test", "Test1")); if (login.User == "Test2") claim.Add(new Claim("Test", "Test2")); if (login.User == "Test3") claim.Add(new Claim("Test", "Test3")); //對稱秘鑰 var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.SecretKey)); //簽名證書(秘鑰,加密演算法) var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); //生成token [註意]需要nuget添加Microsoft.AspNetCore.Authentication.JwtBearer包,並引用System.IdentityModel.Tokens.Jwt命名空間 var token = new JwtSecurityToken(_jwtSettings.Issuer, _jwtSettings.Audience, claim, DateTime.Now, DateTime.Now.AddMinutes(30), creds); return Ok(new { token = new JwtSecurityTokenHandler().WriteToken(token) }); }View Code
4.基於角色的授權
[HttpGet] [Authorize(Roles ="Test")] public ActionResult<string> AuthValue() { var name = User.FindFirst(ClaimTypes.Name)?.Value; var role = User.FindFirst(ClaimTypes.Role)?.Value; _logger.LogInformation($"許可權登錄,用戶名:{name},角色:{role}"); return $"許可權登錄,用戶名:{name},角色:{role}"; }
Roles角色如果有多個,可以以逗號隔開。
5.基於策略的授權
//Startup.cs中添加策略
services.AddAuthorization(options => { options.AddPolicy("OnlyTestAccess", policy => policy.RequireClaim("Test", new string[] { "Test1", "Test2" })); options.AddPolicy("DepartmentAccess", policy => policy.RequireClaim("Department")); });
// 方法上增加策略
[HttpGet] [Authorize(Policy = "OnlyTestAccess")] public ActionResult<string> AuthExtensionValue() { var name = User.FindFirst(ClaimTypes.Name)?.Value; var role = User.FindFirst(ClaimTypes.Role)?.Value; _logger.LogInformation($"基於策略的登錄,用戶名:{name},角色:{role}"); return $"基於策略的登錄,用戶名:{name},角色:{role}"; }
6.運行的截圖
7.Github上的源碼
https://github.com/jasonhua95/samll-project/tree/master/JwtApiDemo