什么是JWT:https://www.cnblogs.com/yan7/p/7857833.html
在前后端分离开发中会需要进行用户验证,本篇博客介绍如何在ASP.NET Core WebApi中使用JWT进行用户认证。
本篇博客延续上一篇博客 https://www.cnblogs.com/gygg/p/12849641.html 配置swagger验证功能
开发工具:Visual Studio2019
目标框架:.NET Core 3.1
一、启用swagger验证功能
1.1、AddSwaggerGen()方法中启用swagger验证功能,添加全局安全条件,自定义Heard Token
services.AddSwaggerGen(c => { //启用swagger验证功能 c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme() { Description = "在下框中输入请求头中需要添加Jwt授权Token:Bearer Token", Name = "Authorization",//jwt默认的参数名称 In = ParameterLocation.Header,//jwt默认存放authorization信息的位置(请求头中) Type = SecuritySchemeType.ApiKey, BearerFormat = "JWT", Scheme = "Bearer" }); //添加全局安全条件 c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme{ Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer"} },new string[] { } } }); //显示自定义的Heard Token c.OperationFilter(); });
1.2、添加 AuthTokenHeaderParameter 类,显示自定义的Heard Token
public class AuthTokenHeaderParameter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { operation.Parameters = operation.Parameters ?? new List(); var isAuthor = operation != null && context != null; if (isAuthor) { //in query header operation.Parameters.Add(new OpenApiParameter() { Name = "Authorization", Description = "身份验证", Required = false, In = ParameterLocation.Header }); } if (!context.ApiDescription.HttpMethod.Equals("POST", StringComparison.OrdinalIgnoreCase) && !context.ApiDescription.HttpMethod.Equals("PUT", StringComparison.OrdinalIgnoreCase)) { return; } } }
启动项目,效果图如下
2、注册JWT
2.1、添加 JWTTokenOptions 类
public class JWTTokenOptions { ////// 订阅者 /// public string Audience { get; set; } ////// 发起人 /// public string Issuer { get; set; } ////// 过期时间 单位秒 /// public long Expire { get; set; } ////// 秘钥 /// public string Secret { get; set; } }
2.2、在 appsettings.json 中配置JWTToken
"JWTToken": { "Expire": 3600, //token过期时间 单位s "Audience": "www.baidu.com", //订阅者 "Issuer": "baidu", //发起人 "Secret": "************************" //秘钥 }
2.3、在 startup 类的 ConfigureServices 方法中注册 jwt
#region 注册jwt JWTTokenOptions JWTTokenOptions = new JWTTokenOptions(); //获取appsettings的内容 services.Configure(this.Configuration.GetSection("JWTToken")); //将给定的对象实例绑定到指定的配置节 Configuration.Bind("JWTToken", JWTTokenOptions); //注册到Ioc容器 services.AddSingleton(JWTTokenOptions); //添加验证服务 services.AddAuthentication(option => { //默认身份验证模式 option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; //默认方案 option.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(option => { //设置元数据地址或权限是否需要HTTP option.RequireHttpsMetadata = false; option.SaveToken = true; //令牌验证参数 option.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, //获取或设置要使用的Microsoft.IdentityModel.Tokens.SecurityKey用于签名验证。 IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII. GetBytes(JWTTokenOptions.Secret)), //获取或设置一个System.String,它表示将使用的有效发行者检查代币的发行者。 ValidIssuer = JWTTokenOptions.Issuer, //获取或设置一个字符串,该字符串表示将用于检查的有效受众反对令牌的观众。 ValidAudience = JWTTokenOptions.Audience, //是否验证发起人 ValidateIssuer = false, //是否验证订阅者 ValidateAudience = false, ////允许的服务器时间偏移量 ClockSkew = TimeSpan.Zero, ////是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比 ValidateLifetime = true }; //如果jwt过期,在返回的header中加入Token-Expired字段为true,前端在获取返回header时判断 option.Events = new JwtBearerEvents() { OnAuthenticationFailed = context => { if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) { context.Response.Headers.Add("Token-Expired", "true"); } return Task.CompletedTask; } }; }); #endregion
2.4、在 startup 类的 Configure 方法中添加认证
app.UseAuthentication(); //添加认证 app.UseAuthorization(); //添加授权(.netCore 3.x中使用)
3、生成JWT
3.1、添加 TokenResult 类
public class TokenResult { ////// token字符串 /// public string Access_token { get; set; } ////// 过期时间 /// public long Expires_in { get; set; } }
3.2、添加 JwtTokenHelper 类
public class JwtTokenHelper { public JwtTokenHelper() { } public TokenResult AuthorizeToken(int memberId, JWTTokenOptions _tokenOptions) { //基于声明的认证 var claims = new[] { new Claim(ClaimTypes.Name,memberId.ToString()), new Claim(JwtRegisteredClaimNames.Jti,Guid.NewGuid().ToString())//jwt的唯一标识 }; //秘钥 转化成UTF8编码的字节数组 var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_tokenOptions.Secret)); var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);//资格证书 秘钥加密 var jwtToken = new JwtSecurityToken(_tokenOptions.Issuer, _tokenOptions.Audience, claims,//发起人 订阅者 expires: DateTime.Now.AddSeconds(_tokenOptions.Expire),//过期时间 signingCredentials: credentials);//秘钥 var securityToken = new JwtSecurityTokenHandler().WriteToken(jwtToken);//序列化jwt格式 //生成令牌字符串 return new TokenResult() { Access_token = "Bearer " + securityToken, Expires_in = _tokenOptions.Expire }; } }
3.3、添加生成 JWT 方法
[ApiController] [Route("api/[controller]/[action]")] public class HomeController : Controller { private readonly JWTTokenOptions _tokenOptions; public HomeController(JWTTokenOptions tokenOptions) { _tokenOptions = tokenOptions; } ////// 生成jwt /// ///[HttpPost] public TokenResult GenerateJwt() { var token = new JwtTokenHelper().AuthorizeToken(123456, _tokenOptions); return token; } }
执行 GenerateJwt 方法,生成 jwt
在需要认证的 Controller 中添加 [Authorize] 特性
若未进行jwt认证,则报错401
若进行了jwt 认证,则正常返回接口
End!