什么是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<AuthTokenHeaderParameter>(); });
1.2、添加 AuthTokenHeaderParameter 類,顯示自定義的Heard Token
public class AuthTokenHeaderParameter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { operation.Parameters = operation.Parameters ?? new List<OpenApiParameter>(); 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 { /// <summary> /// 訂閱者 /// </summary> public string Audience { get; set; } /// <summary> /// 發起人 /// </summary> public string Issuer { get; set; } /// <summary> /// 過期時間 單位秒 /// </summary> public long Expire { get; set; } /// <summary> /// 秘鑰 /// </summary> 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<JWTTokenOptions>(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 { /// <summary> /// token字符串 /// </summary> public string Access_token { get; set; } /// <summary> /// 過期時間 /// </summary> 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; } /// <summary> /// 生成jwt /// </summary> /// <returns></returns> [HttpPost] public TokenResult GenerateJwt() { var token = new JwtTokenHelper().AuthorizeToken(123456, _tokenOptions); return token; } }
執行 GenerateJwt 方法,生成 jwt
在需要認證的 Controller 中添加 [Authorize] 特性
若未進行jwt認證,則報錯401
若進行了jwt 認證,則正常返回接口
End!