本文主要介绍如何在 .NET Core 项目中配置基于 JWT 的 Token 验证。
前言
.NET Core 中使用 Authentication
和
Authorization
来进行权限控制。这两个单词长的十分相似,而且还经常一起出现,很多时候容易搞混了。
Authentication
是认证的意思,当用户请求到来时,判断用户是否是合法的,比如用户名密码是否正确,token
是否合法且有效等等。它是 Web 服务的第一道门。
Authorization
是授权的意思,当用户通过认证后,还需要验证是否有访问某个接口的权限。授权使用
Authorize
在 Action(方法) 上进行标标记。
默认情况下,认证通过即认为有权限访问相关的接口。也可以基于角色、策略、自定义的方式来实现接口的授权。
配置 JWT 授权
本文使用的 .NET Core 版本为 6.1
安装包
使用 jwt 验证需要安装两个包:
System.IdentityModel.Tokens.Jwt
Microsoft.AspNetCore.Authentication.JwtBearer
添加 Token 配置
在 appsettings.json 添加如下内容:
1 2 3 4 5 6 "TokenParam" : { "Secret" : "15927306782" , "Expire" : 43200000 , "Issuer" : "wowToolAPI" , "Audience" : "everybody" } ,
添加 JWT 服务配置
在 Program.cs 中的 var app = builder.Build();
前添加一个服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 var secret = builder.Configuration["TokenParam:Secret" ];services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(x => { x.RequireHttpsMetadata = false ; x.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true , IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret)), ValidateIssuer = false , ValidateAudience = false ValidateLifetime = true , ClockSkew = TimeSpan.FromMinutes(1440 ) }; });
添加验证中间件
在 Program.cs 中添加下列代码:
1 2 3 4 app.UseAuthentication(); app.UseAuthorization();
上述两个中间件必须要同时添加,顺序也不能错
在 Controller 中添加授权控制
需要在 Controller 或者 Action 上添加 [Authorize]
特性,该特性表明当前 Controller 或 Action 需要先进行授权验证。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class AController : ControllerBase { public string Get () { return "666" ; } } [Authorize ] public class BController : ControllerBase { public string Get () { return "666" ; } } public class CController : ControllerBase { [Authorize ] public string Get () { return "666" ; } public string GetB () { return "666" ; } } [Authorize ] public class DController : ControllerBase { [AllowAnonymous ] public string Get () { return "666" ; } }
一次将授权添加到所有的
Controller 上
在开发中,一般只有个别 API 不需要权限认证,如果每添加一个
Controller,都在上面标记
[Authorize]
,使用起来挺难受的。
有没有办法只在一个地方设置一次,全部 Controller 都添加了呢?
当然,咱们可以先添加一个基类,在这个类上添加 [Authorize]
特性。然后其它的 Controller 只要继承这个基类就可以了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class MyControllerBase : ControllerBase { } [Authorize ] public class EController : MyControllerBase { } [AllowAnonymous ] public class FController : MyControllerBase { }
生成 JWT token
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public static string CreateToken (this TokenParams tokenParam, Dictionary<string , string > payload ){ var claims = new List<Claim>(); if (payload != null ) { claims = payload.ToList().ConvertAll(kv => { return new Claim(kv.Key, kv.Value); }); } SymmetricSecurityKey key = new (Encoding.UTF8.GetBytes(tokenParam.Secret)); JwtSecurityToken token = new ( issuer: tokenParam.Issuer, audience: tokenParam.Audience, claims: claims, notBefore: DateTime.Now, expires: DateTime.Now.AddMinutes(1440 ), signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256) ); string jwtToken = new JwtSecurityTokenHandler().WriteToken(token); return jwtToken; }
从请求中获取 JWT
从请求中获取 token 字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 protected string GetToken (){ string tokenHeader = Request.Headers[HeaderNames.Authorization].ToString(); if (string .IsNullOrEmpty(tokenHeader)) throw new ArgumentNullException("缺少token!" ); string pattern = "^Bearer (.*?)$" ; if (!Regex.IsMatch(tokenHeader, pattern)) throw new Exception("token格式不对!格式为:Bearer {token}" ); string ? token = Regex.Match(tokenHeader, pattern)?.Groups[1 ]?.ToString(); if (string .IsNullOrEmpty(token)) throw new Exception("token不能为空!" ); return token; }
解析 token
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public static Result<JObject> GetTokenPayload (this TokenParams tokenParam, string token ){ var validateParameter = new TokenValidationParameters() { ValidateLifetime = true , ValidateAudience = true , ValidateIssuer = true , ValidateIssuerSigningKey = true , ValidIssuer = tokenParam.Issuer, ValidAudience = tokenParam.Audience, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenParam.Secret)) }; new JwtSecurityTokenHandler().ValidateToken(token, validateParameter, out SecurityToken validatedToken); var jwtPayload = ((JwtSecurityToken)validatedToken).Payload.SerializeToJson(); var jobj = JObject.Parse(jwtPayload); return jobj; }
参考
ASP.NET
Core 中jwt授权认证的流程原理
UseAuthentication和UseAuthorization
https://zhuanlan.zhihu.com/p/176966592
ASP.NET
Core 6.0 添加 JWT 认证和授权