WebApi必須保證安全,現在來添加JWT認證
1、打開appsettings.json添加JWT認證的配置信息
2、在項目根目錄下新建一個Models文件夾,添加一個JwtSettings.cs的實體

1 namespace Dinner.WebApi.Models 2 { 3 public class JwtSettings 4 { 5 /// <summary> 6 /// 證書頒發者 7 /// </summary> 8 public string Issuer { get; set; } 9 10 /// <summary> 11 /// 允許使用的角色 12 /// </summary> 13 public string Audience { get; set; } 14 15 /// <summary> 16 /// 加密字符串 17 /// </summary> 18 public string SecretKey { get; set; } 19 } 20 }
3、Startup.cs文件中的ConfigureServices添加Jwt認證的代碼

1 #region JWT認證 2 3 services.Configure<JwtSettings>(Configuration.GetSection("JwtSettings")); 4 JwtSettings setting = new JwtSettings(); 5 //綁定配置文件信息到實體 6 Configuration.Bind("JwtSettings", setting); 7 //添加Jwt認證 8 services.AddAuthentication(option => 9 { 10 option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; 11 option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; 12 }).AddJwtBearer(config => 13 { 14 config.TokenValidationParameters = new TokenValidationParameters 15 { 16 ValidAudience = setting.Audience, 17 ValidIssuer = setting.Issuer, 18 IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(setting.SecretKey)) 19 }; 20 /* 21 config.SecurityTokenValidators.Clear(); 22 config.SecurityTokenValidators.Add(new MyTokenValidate()); 23 config.Events = new JwtBearerEvents() 24 { 25 OnMessageReceived = context => 26 { 27 var token = context.Request.Headers["myToken"]; 28 context.Token = token.FirstOrDefault(); 29 return Task.CompletedTask; 30 } 31 }; 32 */ 33 }); 34 35 #endregion
4、Startup.cs文件中的Configure添加Jwt認證的代碼

1 app.UseAuthentication();
5、基本配置都弄完了,現在是生成JwtToken,在ValuesController中添加一個生成Jwt的Action

1 using Dinner.WebApi.Models; 2 using Microsoft.AspNetCore.Mvc; 3 using Microsoft.Extensions.Options; 4 using Microsoft.IdentityModel.Tokens; 5 using System; 6 using System.Collections.Generic; 7 using System.IdentityModel.Tokens.Jwt; 8 using System.Security.Claims; 9 using System.Text; 10 11 namespace Dinner.WebApi.Controllers 12 { 13 [Route("api/[controller]/[action]")] 14 public class ValuesController : Controller 15 { 16 private readonly JwtSettings setting; 17 public ValuesController(IOptions<JwtSettings> _setting) 18 { 19 setting = _setting.Value; 20 } 21 // GET api/values 22 [HttpGet] 23 public IEnumerable<string> Get() 24 { 25 return new string[] { "value1", "value2" }; 26 } 27 28 // GET api/values/5 29 [HttpGet("{id}")] 30 public string Get(int id) 31 { 32 return "value"; 33 } 34 35 // POST api/values 36 [HttpPost] 37 public void Post([FromBody]string value) 38 { 39 } 40 41 // PUT api/values/5 42 [HttpPut("{id}")] 43 public void Put(int id, [FromBody]string value) 44 { 45 } 46 47 // DELETE api/values/5 48 [HttpDelete("{id}")] 49 public void Delete(int id) 50 { 51 } 52 53 [HttpGet] 54 public IActionResult GetGenerateJWT() 55 { 56 try 57 { 58 var claims = new Claim[] 59 { 60 new Claim(ClaimTypes.Name, "wangshibang"), 61 new Claim(ClaimTypes.Role, "admin, Manage") 62 }; 63 var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(setting.SecretKey)); 64 var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); 65 var token = new JwtSecurityToken( 66 setting.Issuer, 67 setting.Audience, 68 claims, 69 DateTime.Now, 70 DateTime.Now.AddMinutes(30), 71 creds); 72 return Ok(new { Token = new JwtSecurityTokenHandler().WriteToken(token) }); 73 } 74 catch (Exception ex) 75 { 76 return BadRequest(ex.Message); 77 } 78 79 } 80 } 81 }
這樣調用這個方法就會生成一個JwtToken,然后在UsersController上面添加一個[Authorize]的特性
上一篇我們說過SwaggerUI配置的最后一句有一個options.OperationFilter<HttpHeaderOperation>(); 這里我們來看這個HttpHeaderOperation

1 using Microsoft.AspNetCore.Authorization; 2 using Swashbuckle.AspNetCore.Swagger; 3 using Swashbuckle.AspNetCore.SwaggerGen; 4 using System.Collections.Generic; 5 using System.Linq; 6 7 namespace Dinner.WebApi 8 { 9 public class HttpHeaderOperation : IOperationFilter 10 { 11 public void Apply(Operation operation, OperationFilterContext context) 12 { 13 if (operation.Parameters == null) 14 { 15 operation.Parameters = new List<IParameter>(); 16 } 17 18 var actionAttrs = context.ApiDescription.ActionAttributes(); 19 20 var isAuthorized = actionAttrs.Any(a => a.GetType() == typeof(AuthorizeAttribute)); 21 22 if (isAuthorized == false) //提供action都沒有權限特性標記,檢查控制器有沒有 23 { 24 var controllerAttrs = context.ApiDescription.ControllerAttributes(); 25 26 isAuthorized = controllerAttrs.Any(a => a.GetType() == typeof(AuthorizeAttribute)); 27 } 28 29 var isAllowAnonymous = actionAttrs.Any(a => a.GetType() == typeof(AllowAnonymousAttribute)); 30 31 if (isAuthorized && isAllowAnonymous == false) 32 { 33 operation.Parameters.Add(new NonBodyParameter() 34 { 35 Name = "Authorization", //添加Authorization頭部參數 36 In = "header", 37 Type = "string", 38 Required = false 39 }); 40 } 41 } 42 } 43 }
這個代碼主要就是在swagger頁面添加了一個Authorization的頭部輸入框信息,以便來進行驗證
現在我們基本工作都做好了,打開頁面測試吧,注意:傳入的Authorization參數必須是Bearer xxxxxxx的形式(xxxxxxx為生成的Token)
他返回了Http200就是成功了
整個項目的框架基本算是搭建好了,這只是一個雛形而已,其實Authorize這一塊需要建一個BaseController繼承Controller再在BaseController上添加一個Authorize然后所有Controller繼承BaseController就不用一個一個的寫Authorize了,不需要驗證的加個AllowAnonymous就可以了,其他的直接擴展倉儲接口寫倉儲就可以直接調用了
源碼地址: https://github.com/wangyulong0505/Dinner