JWT Token 使用方法
一、安装 Microsoft.AspNetCore.Authentication.JwtBearer 包 选择需要使用的版本
二、创建一个类库,存放数据并引用
using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; using System; using System.Collections.Generic; using System.Security.Claims; using System.Text; using System.IdentityModel.Tokens.Jwt; namespace JwtAuthDemo.Helpers { public class JwtHelpers { private readonly IConfiguration Configuration; public JwtHelpers(IConfiguration configuration) { this.Configuration = configuration; } public string GenerateToken(string userName, int expireMinutes = 30) { var issuer = Configuration.GetValue<string>("JwtSettings:Issuer"); var signKey = Configuration.GetValue<string>("JwtSettings:SignKey"); // 設定要加入到 JWT Token 中的聲明資訊(Claims) var claims = new List<Claim>(); // 在 RFC 7519 規格中(Section#4),總共定義了 7 個預設的 Claims,我們應該只用的到兩種! //claims.Add(new Claim(JwtRegisteredClaimNames.Iss, issuer)); claims.Add(new Claim(JwtRegisteredClaimNames.Sub, userName)); // User.Identity.Name //claims.Add(new Claim(JwtRegisteredClaimNames.Aud, "The Audience")); //claims.Add(new Claim(JwtRegisteredClaimNames.Exp, DateTimeOffset.UtcNow.AddMinutes(30).ToUnixTimeSeconds().ToString())); //claims.Add(new Claim(JwtRegisteredClaimNames.Nbf, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString())); // 必須為數字 //claims.Add(new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString())); // 必須為數字 claims.Add(new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())); // JWT ID // 網路上常看到的這個 NameId 設定是多餘的 //claims.Add(new Claim(JwtRegisteredClaimNames.NameId, userName)); // 這個 Claim 也以直接被 JwtRegisteredClaimNames.Sub 取代,所以也是多餘的 //claims.Add(new Claim(ClaimTypes.Name, userName)); // 你可以自行擴充 "roles" 加入登入者該有的角色 claims.Add(new Claim("roles", "Admin")); claims.Add(new Claim("roles", "Users")); var userClaimsIdentity = new ClaimsIdentity(claims); // 建立一組對稱式加密的金鑰,主要用於 JWT 簽章之用 var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(signKey)); // HmacSha256 有要求必須要大於 128 bits,所以 key 不能太短,至少要 16 字元以上 // https://stackoverflow.com/questions/47279947/idx10603-the-algorithm-hs256-requires-the-securitykey-keysize-to-be-greater var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature); // 建立 SecurityTokenDescriptor var tokenDescriptor = new SecurityTokenDescriptor { Issuer = issuer, //Audience = issuer, // 由於你的 API 受眾通常沒有區分特別對象,因此通常不太需要設定,也不太需要驗證 //NotBefore = DateTime.Now, // 預設值就是 DateTime.Now //IssuedAt = DateTime.Now, // 預設值就是 DateTime.Now Subject = userClaimsIdentity, Expires = DateTime.Now.AddMinutes(expireMinutes), SigningCredentials = signingCredentials }; // 產出所需要的 JWT securityToken 物件,並取得序列化後的 Token 結果(字串格式) var tokenHandler = new JwtSecurityTokenHandler(); var securityToken = tokenHandler.CreateToken(tokenDescriptor); var serializeToken = tokenHandler.WriteToken(securityToken); return serializeToken; } } }
三、在appsettings.json 添加数据
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "JwtSettings": { "Issuer": "JwtAuthDemo", "SignKey": "134oskqkflps63055" //固定 长度大于十六位以上的字符串 } }
四、在Startup.cs添加注入
services.AddSingleton<JwtHelpers>();
五、使用的方法
1、创建一个model
public class LoginViewModel { public string UserName { get; set; } public string Password { get; set; } }
2、控制器使用
using JwtAuthDemo.Helpers; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using lianxi_JWT_Token.Model; namespace lianxi_JWT_Token.Controllers { //授权 [Authorize] [Route("api/[controller]")] [ApiController] public class LoginController : ControllerBase { public readonly JwtHelpers _jwtHelpers; public LoginController(JwtHelpers jwtHelpers) { _jwtHelpers = jwtHelpers; } //任何请求都可以访问该方法 [AllowAnonymous] [HttpPost, Route("login")] public IActionResult Login(LoginViewModel login) { if(ValidateUser(login)) { var token = _jwtHelpers.GenerateToken(login.UserName); HttpContext.Response.Headers.Add("token", token); return Ok(); } else { //失败的请求 状态码400 return BadRequest(); } } [HttpGet] public bool ValidateUser(LoginViewModel login) { return true; } [Authorize] [HttpGet,Route("Test")] public IActionResult Test() { return Ok("Test"); } } }
3、在Startup.cs添加验证
services .AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { // 當驗證失敗時,回應標頭會包含 WWW-Authenticate 標頭,這裡會顯示失敗的詳細錯誤原因 options.IncludeErrorDetails = true; // 預設值為 true,有時會特別關閉 options.TokenValidationParameters = new TokenValidationParameters { // 透過這項宣告,就可以從 "sub" 取值並設定給 User.Identity.Name NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", // 透過這項宣告,就可以從 "roles" 取值,並可讓 [Authorize] 判斷角色 RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role", // 一般我們都會驗證 Issuer ValidateIssuer = true, ValidIssuer = Configuration.GetValue<string>("JwtSettings:Issuer"), // 通常不太需要驗證 Audience ValidateAudience = false, //ValidAudience = "JwtAuthDemo", // 不驗證就不需要填寫 // 一般我們都會驗證 Token 的有效期間 ValidateLifetime = true, // 如果 Token 中包含 key 才需要驗證,一般都只有簽章而已 ValidateIssuerSigningKey = false, // "1234567890123456" 應該從 IConfiguration 取得 IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetValue<string>("JwtSettings:SignKey"))) }; });
4、引用
app.UseAuthentication();
5、开启Swagger认证
开启Swagger认证 c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme() { Description = "在下框中输入请求头中需要添加Jwt授权Token:Bearer Token", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.ApiKey, BearerFormat = "JWT", Scheme = "Bearer" }); c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] { } } });
6、Startup显示
using JwtAuthDemo.Helpers; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace lianxi_JWT_Token { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "lianxi_JWT_Token", Version = "v1" }); #region 开启Swagger认证 c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme() { Description = "在下框中输入请求头中需要添加Jwt授权Token:Bearer Token", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.ApiKey, BearerFormat = "JWT", Scheme = "Bearer" }); c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] { } } }); #endregion }); //通过AddSingleton services.AddSingleton<JwtHelpers>(); //验证 services .AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { // 當驗證失敗時,回應標頭會包含 WWW-Authenticate 標頭,這裡會顯示失敗的詳細錯誤原因 options.IncludeErrorDetails = true; // 預設值為 true,有時會特別關閉 options.TokenValidationParameters = new TokenValidationParameters { // 透過這項宣告,就可以從 "sub" 取值並設定給 User.Identity.Name NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/ nameidentifier", // 透過這項宣告,就可以從 "roles" 取值,並可讓 [Authorize] 判斷角色 RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role", // 一般我們都會驗證 Issuer ValidateIssuer = true, ValidIssuer = Configuration.GetValue<string>("JwtSettings:Issuer"), // 通常不太需要驗證 Audience ValidateAudience = false, //ValidAudience = "JwtAuthDemo", // 不驗證就不需要填寫 // 一般我們都會驗證 Token 的有效期間 ValidateLifetime = true, // 如果 Token 中包含 key 才需要驗證,一般都只有簽章而已 ValidateIssuerSigningKey = false, // "1234567890123456" 應該從 IConfiguration 取得 IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes (Configuration.GetValue<string>("JwtSettings:SignKey"))) }; }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "lianxi_JWT_Token v1")); } app.UseRouting(); //验证 app.UseAuthentication(); //授权 app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } } }
......待续