在netCore中,微软把授权和认证分开了,先授权,再进行认证,本篇文章,用来介绍JWt在NetCore的使用
根据不同的登录用户而言,拥有着不一样的权限,在介绍之前要知道一下几点
1.知道identity是什么,他是个身份
2.知道 Claim 是什么,可以理解为证件
3.知道授权里面的 Policy,授权策略
一:先安装 Microsoft.AspNetCore.Authentication.JwtBearer
二:在 Startup 中
1 public Startup(IConfiguration configuration) 2 { 3 Configuration = configuration; 4 } 5 6 public IConfiguration Configuration { get; } 7 8 public void ConfigureServices(IServiceCollection services) 9 { 10 services.AddMvc(); 11 12 //授权 13 services.AddAuthorization(options => 14 { 15 // 添加授权的策略, 16 //通过代码,可以看出 一个授权策略是可以包含多个用户的角色的,是不是有点像“角色用户分组” 17 options.AddPolicy("Admin", policy => policy.RequireRole("Admin").Build()); 18 options.AddPolicy("SystemOrAdmin", policy => policy.RequireRole("test", "System")); // 就像是 SystemOrAdmin就是组名,成员有角色test和角色System 19 }); 20 21 //认证 22 services.AddAuthentication(options => 23 { 24 options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; 25 options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; 26 }) 27 .AddJwtBearer(cfg => 28 { 29 cfg.RequireHttpsMetadata = false;// 获取或设置元数据地址或权限是否需要https。这个 默认值为true。这应该只在开发环境中禁用。 30 cfg.SaveToken = true; //定义承载令牌是否应存储在Microsoft.aspnetcore.http.authentication.authenticationproperties中 在成功授权之后。 31 32 // TokenValidationParameters:获取或设置用于验证标识令牌的参数。 33 cfg.TokenValidationParameters = new TokenValidationParameters() 34 { 35 ValidIssuer = Configuration["Tokens:Issuer"], //获取或设置表示将使用的有效颁发者的System.String。 检查令牌的颁发者。 36 ValidAudience = Configuration["Tokens:Issuer"], //获取或设置一个字符串,该字符串表示将用于检查的有效访问群体。 反对代币的观众。 37 IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Tokens:Key"])) // 获取或设置要使用的Microsoft.IdentityModel.Tokens.SecurityKey。用于签名验证。 38 }; 39 JwtBearerEvents events = new JwtBearerEvents 40 { 41 //请求出现异常时,调用这个 42 OnAuthenticationFailed = context => 43 { 44 // 判断token是否已经过期 45 if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) 46 { 47 context.Response.Headers.Add("Token-Expired", "true"); //如果已经过期,加一个header头部 48 49 using (StreamWriter streamWriter = new StreamWriter(context.Response.Body, Encoding.UTF8)) 50 streamWriter.Write("你的token已经过期了"); 51 52 } 53 return Task.CompletedTask; 54 } 55 }; 56 cfg.Events = events; 57 }); 58 }
加入 app.UseAuthentication(); ,要在 app.UseMvc(); 之前
三:写个AuthController,写个登录方法
1 [HttpPost] 2 public IActionResult Login([FromBody] AuthRequest authUserRequest) 3 { 4 if (authUserRequest == null) 5 return BadRequest("没找到登录用户");//Could not create token,返回 400 Bad Request 6 if (authUserRequest.UserName != "test" || authUserRequest.Password != "test") 7 return BadRequest("用户名或者密码输入错误");//Could not create token 8 9 // 1.写好这个证件中,有哪些信息,一个Claim 对象代表着一个证件中某一个信息 10 Claim[] claims = new[] 11 { 12 new Claim(JwtRegisteredClaimNames.UniqueName, authUserRequest.UserName), //证件用户名 13 new Claim(JwtRegisteredClaimNames.Sid, authUserRequest.UserId),// 证件Id 14 15 new Claim(ClaimTypes.Role, "test") //证件的角色,以后控制器上就可以直接这样写 [Authorize(Roles = "test")] 16 }; 17 18 19 // 2. 准备 安全密钥。 20 SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this._config["Tokens:Key"])); 21 //3.准备 数字签名的安全密钥、算法和摘要。 22 SigningCredentials creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); 23 24 //4.实例化JWT得到token, 25 JwtSecurityToken jst = new JwtSecurityToken( 26 issuer : this._config["Tokens:Issuer"], 27 audience: this._config["Tokens:Issuer"], 28 claims: claims, 29 expires: DateTime.Now.AddMinutes(30), 30 signingCredentials: creds 31 ); 32 33 // 5. 以精简序列化格式将JWT安全令牌序列化为WT。拿到最终的token 34 string token = new JwtSecurityTokenHandler().WriteToken(jst); 35 36 return Ok(new 37 { 38 token, 39 expiration = jst.ValidTo //获取已转换为System.DateTime的“过期”声明{exp,“值”}的“值”。 假设'value'是unixepoch(UTC 1970 - 01 - 01t0:0:0z)之后的秒数。拿到过期的时间 40 }); 41 42 }
再写个需要授权才能访问的控制,ValuesController
1 [Route("api/[controller]")] 2 //[Authorize] 这么写,完全就是一个检查token的作用,没有检查角色 3 //[Authorize(Policy = "SystemOrAdmin")] 等价于 [Authorize("SystemOrAdmin")] 4 5 // [Authorize(Roles = "test")] 6 //[Authorize(Policy = "SystemOrAdmin")] 7 [Authorize("SystemOrAdmin")] 8 public class ValuesController : Controller 9 { 10 // GET api/values 11 [HttpGet] 12 public IEnumerable<string> Get() 13 { 14 return new string[] { "授权成功", "value2", "value3", "value4", "value5" }; 15 } 16 }
打开这个页面,直接点击GetData,由于没有授权,就报的401
GetData调用的接口是value控制器中的Get方法
当点击登录后,再点击Getdata就是成功的。如果当前登录用户的角色,没有认证成功,返回403给你
要注意的是:[Authorize(Roles = "test")] ,表示当前 Claim.Role=“test”,才能进来,那么在登录的时候,就要当前登录成功的用户写进 Claim 中,以及当前登录用户所对应的权限
[Authorize(Policy = "SystemOrAdmin")],Policy 是一个授权策略,他里面包含着多中用户角色,就是某一组用户角色组名,他的配置也在 ConfigureServices 写好, services.AddAuthorization ,添加授权里面,写上。
还有一点是,利用微软官方的认证机制,如果没有授权成功,及授权失败,他都是直接返回 Http状态码,但是你希望,返回一个view或者一段json?或者说是 把当前登录用户信息,写进HttpContex.User?
1 这时候,就需要自己手动写个类,继承 IAuthorizationRequirement, 2 来完成 整个认证的过程,返回什么由自己定义 3 //注入 我们自定义的权限处理器,替换微软Core自带的 权限检查处理, 4 //PermissionHandler类是我们自定义认证逻辑类 5 services.AddSingleton<IAuthorizationHandler, PermissionHandler>();