NetCore+Dapper WebApi架构搭建(六):添加JWT认证
WebApi必须保证安全,现在来添加JWT认证
1、打开appsettings.json添加JWT认证的配置信息
2、在项目根目录下新建一个Models文件夹,添加一个JwtSettings.cs的实体
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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认证的代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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认证的代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 app.UseAuthentication();
5、基本配置都弄完了,现在是生成JwtToken,在ValuesController中添加一个生成Jwt的Action
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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