Asp.net Core认证和授权:JWT认证和授权
2019-01-24 21:24 糯米粥 阅读(5411) 评论(0) 编辑 收藏 举报JWT验证一般用户移动端,因为它不像cookie验证那样,没有授权跳转到登陆页面
JWT是json web token的简称,在 jwt.io 网址可以看到
新建一个API项目,通过postman 可以访问:
JWT在命名空间:using Microsoft.AspNetCore.Authentication.JwtBearer;
添加JWT实体类
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Api.Models { public class JwtSettings { /// <summary> /// Token是谁颁发的 /// </summary> public string Issuer { get; set; } /// <summary> /// Token给那些客户端去使用 /// </summary> public string Audience { get; set; } /// <summary> /// 用于加密的key 必须是16个字符以上,要大于128个字节 /// </summary> public string SecetKey { get; set; } } }
添加配置文件
添加JWT认证
public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.Configure<JwtSettings>(Configuration); var jwtSettings = new JwtSettings(); Configuration.Bind("JwtSettings", jwtSettings); services.AddAuthentication(option => { option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(option=> { option.TokenValidationParameters = new TokenValidationParameters { ValidIssuer = jwtSettings.Issuer, ValidAudience = jwtSettings.Audience, IssuerSigningKey=new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecetKey))
/***********************************TokenValidationParameters的参数默认值***********************************/
// RequireSignedTokens = true,
// SaveSigninToken = false,
// ValidateActor = false,
// 将下面两个参数设置为false,可以不验证Issuer和Audience,但是不建议这样做。
// ValidateAudience = true,
// ValidateIssuer = true,
// ValidateIssuerSigningKey = false,
// 是否要求Token的Claims中必须包含Expires
// RequireExpirationTime = true,
// 允许的服务器时间偏移量
// ClockSkew = TimeSpan.FromSeconds(300),
// 是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比
// ValidateLifetime = true }; }); }
添加中间件(Middleware)
app.UseAuthentication();
API接口打上标签:
然后在postman访问 就是401 未授权
接下来需要给用户颁发Token
当用户登陆成功后,颁发token
创建登陆API和实体类
namespace Api.Models { public class LoginViewModel { [Required] public string user { get; set; } [Required] public string pwd { get; set; } } }
using Api.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using System; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; namespace Api.Controllers { //[Route("api/[controller]")] //[ApiController] public class AuthorizeController : ControllerBase { private JwtSettings _jwtSettings; public AuthorizeController(IOptions<JwtSettings> jwtSetting) { _jwtSettings = jwtSetting.Value; } [HttpPost] public IActionResult Token([FromBody]LoginViewModel login) { if (ModelState.IsValid) { if (!(login.user == "cnglgos" && login.pwd == "123")) { return BadRequest(); } var claim = new Claim[] { new Claim("name","cnbogs"), new Claim("role","admin") }; var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.SecretKey)); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); //neget包:Microsoft.AspNetCore.Authentication.JwtBearer //命名空间: System.IdentityModel.Tokens.Jwt; //第一种方式 var token = new JwtSecurityToken( _jwtSettings.Issuer,// Issuer 颁发者,通常为STS服务器地址 _jwtSettings.Audience,// Audience Token的作用对象,也就是被访问的资源服务器授权标识 claim, DateTime.Now, //Token生效时间,在此之前不可用 DateTime.Now.AddMinutes(30), //Token过期时间,在此之后不可用 creds); //第二种方式 var descriptor = new SecurityTokenDescriptor { Issuer = _jwtSettings.Issuer, Audience = _jwtSettings.Audience,// Audience Token的作用对象,也就是被访问的资源服务器授权标识 Subject = new ClaimsIdentity(claim), NotBefore = DateTime.Now, //Token生效时间,在此之前不可用 Expires = DateTime.Now.AddMinutes(30), //Token过期时间,在此之后不可用 SigningCredentials = creds, IssuedAt=DateTime.Now //Token颁发时间 }; var handler = new JwtSecurityTokenHandler(); JwtSecurityToken token1 = handler.CreateJwtSecurityToken(descriptor); return Ok(new { token = new JwtSecurityTokenHandler().WriteToken(token), token1 = handler.WriteToken(token1) }); } return BadRequest(); } public IActionResult Index() { return Ok(); } } }
Postman请求
然后上面的Token 请求 https://localhost:5001/api/values
从headers可以看到,前缀必须是Bearer
我们可以自定义Token,必须继承接口:ISecurityTokenValidator
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using System.Collections.Generic; using System.Security.Claims; namespace Api.Models { public class TokenValidtor : ISecurityTokenValidator { public bool CanValidateToken => true; public int MaximumTokenSizeInBytes { get; set; } public bool CanReadToken(string securityToken) { return true; } public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken) { validatedToken = null;
var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme);
if (securityToken == "cnblgos")
{
var claim = new List<Claim> {
new Claim("name","cnblogs"),
new Claim("role","admin")
};
identity.AddClaims(claim);
}
var principal = new ClaimsPrincipal(identity);
return principal; } } }
然后在StartUp中修改:
public void ConfigureServices(IServiceCollection services) { services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); /* appsettings.json文件中JwtSettings是单独的一节, 所以要GetSection方法获取 */ services.Configure<JwtSettings>(Configuration.GetSection("JwtSettings")); //services.Configure<JwtSettings>(Configuration); var jwtSettings = new JwtSettings(); Configuration.Bind("JwtSettings", jwtSettings); services.AddAuthentication(option => { option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(option => { //option.TokenValidationParameters = new TokenValidationParameters { // ValidIssuer = jwtSettings.Issuer, // ValidAudience = jwtSettings.Audience, // IssuerSigningKey=new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey)) option.SecurityTokenValidators.Clear(); option.SecurityTokenValidators.Add(new TokenValidtor()); option.Events = new JwtBearerEvents { OnMessageReceived = context => { var token = context.Request.Headers["token"]; context.Token = token.FirstOrDefault(); return Task.CompletedTask; } }; }); }
//添加Policy和Claim授权
services.AddAuthorization(options => {
options.AddPolicy("nsky", policy => policy.RequireClaim("nsky")); });
Token可以去jwt.io 网站验证
参考大神的文章:https://www.cnblogs.com/RainingNight/p/jwtbearer-authentication-in-asp-net-core.html