Asp.net Core认证和授权:JWT认证和授权

时间:2021-08-12 12:19:02

JWT验证一般用户移动端,因为它不像cookie验证那样,没有授权跳转到登陆页面

JWT是json web token的简称,在  jwt.io 网址可以看到

Asp.net Core认证和授权:JWT认证和授权

Asp.net Core认证和授权:JWT认证和授权

新建一个API项目,通过postman 可以访问:

Asp.net Core认证和授权:JWT认证和授权

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; }
}
}

添加配置文件

Asp.net Core认证和授权:JWT认证和授权

添加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接口打上标签:

Asp.net Core认证和授权:JWT认证和授权

然后在postman访问 就是401 未授权

Asp.net Core认证和授权:JWT认证和授权

接下来需要给用户颁发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 == ""))
{
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(), //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(), //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请求

Asp.net Core认证和授权:JWT认证和授权

然后上面的Token 请求 https://localhost:5001/api/values

Asp.net Core认证和授权:JWT认证和授权

从headers可以看到,前缀必须是Bearer

Asp.net Core认证和授权:JWT认证和授权

我们可以自定义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")); });

Asp.net Core认证和授权:JWT认证和授权

Asp.net Core认证和授权:JWT认证和授权

Token可以去jwt.io 网站验证

参考大神的文章:https://www.cnblogs.com/RainingNight/p/jwtbearer-authentication-in-asp-net-core.html