asp.net core 集成JWT身份验证

1、【什么是JWT】

  •  JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案。
  • JWT的官网地址:https://jwt.io/
  • 通俗地来讲,JWT是能代表用户身份的令牌,可以使用JWT令牌在api接口中校验用户的身份以确认用户是否有访问api的权限。
  • JWT中包含了身份认证必须的参数以及用户自定义的参数,JWT可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。

2、【什么时候应该使用JSON Web令牌?】

1.授权:这是使用JWT的最常见方案。一旦用户登录,每个后续请求将包括JWT,允许用户访问该令牌允许的路由,服务和资源。Single Sign On是一种现在广泛使用JWT的功能,因为它的开销很小,并且能够在不同的域中轻松使用。

2.信息交换:JSON Web令牌是在各方之间安全传输信息的好方法。因为JWT可以签名 — 例如,使用公钥/私钥对 — 您可以确定发件人是他们所说的人。此外,由于使用标头和有效负载计算签名,您还可以验证内容是否未被篡改。

3、【JWT令牌结构】

在紧凑的形式中,JSON Web Token­s由­dot(.)分隔的三个部分组成,它们是:

  • Head­er 头
  • Pay­load 有效载荷
  • Sig­na­ture 签名

因此,JWT通常如下所示:

  xxxxx.yyyyy.zzzzz

1.Header 头

 标头通常由两部分组成:令牌的类型,即JWT,以及正在使用的签名算法,例如HMAC SHA256或RSA。

  例如:

{
  "alg": "HS256",
  "typ": "JWT"
}

然后,这个JSON被编码为Base64Url,形成JWT的第一部分。

2.Payload 有效载荷

Pay­load 部分也是一个 JSON 对象,用来存放实际需要传递的数据。JWT 规定了7个官方字段,供选用。

  • iss (issuer):签发人
  • exp (expi­ra­tion time):过期时间
  • sub (subject):主题
  • aud (audience):受众
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间
  • jti (JWT ID):编号

加密之后得到的­to­ken样式分为三部分组成。

如果您想使用JWT并将这些概念付诸实践,您可以使用jwt.io Debug­ger来解码,验证和生成JWT。

废话不多说,下面直接上代码(依赖注入使用Visu­al Stu­dio 2022):

首先我们新建一个De­mo asp.net core 空web项目

新建Token控制器,代码如下:

  [Route("api/[controller]/[action]")]
    [ApiController]
    public class TokenController : ControllerBase
    {
        private readonly IConfiguration _configuration;
        public TokenController(IConfiguration configuration)
        {
            _configuration = configuration;
        }
        public IActionResult GetToken(UserLoginInputDtoModel userLoginInput)
        {

           if (userLoginInput.UserName != "admin" && userLoginInput.Password != "admin")
                return BadRequest("账号错误");

           DateTime nowDateTime = DateTime.Now;

           IConfigurationSection jwtConfig = _configuration.GetSection("Jwt");
           string JsonWebKey= SecurityAlgorithms.HmacSha512;

           string secret= jwtConfig.GetValue<string>("Secret");

           SigningCredentials securityKey = new SigningCredentials(new SymmetricSecurityKey
(Encoding.ASCII.GetBytes(secret)), JsonWebKey);

           List<Claim> claims = new List<Claim>
           {
               new Claim(JwtRegisteredClaimNames.Iss, jwtConfig.GetValue<string>("Issuer")),
               new Claim(JwtRegisteredClaimNames.Aud, jwtConfig.GetValue<string>("Audience")),
               new Claim(JwtRegisteredClaimNames.Name, userLoginInput.UserName),
               new Claim(JwtRegisteredClaimNames.Email, userLoginInput.Password),
               new Claim("ex",nowDateTime.ToString(CultureInfo.InvariantCulture))
           };

           SecurityToken securityToken = new JwtSecurityToken(
               signingCredentials: securityKey,
               expires: nowDateTime.AddMinutes(1),//过期时间
               
               claims: claims
           );

           return Content(new JwtSecurityTokenHandler().WriteToken(securityToken));
        }

这里就可以得到一个­to­ken值。

得到token值之后怎么做拦截呢?比如token验证未通过把请求拦截下来,这是就需要用到JWT校验事件了。具体做法如下:

在需要验证的控制器或方法上打上[Autho­rize]标记,如:

        [Authorize]
        public IActionResult GetTodo()
        {
            return Content("ddd");
        }

验证事件在Program.cs(配置信息在appsettings.json中配置)中编写,如下:

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseUrls("http://192.168.1.110:9010");
// Add services to the container.
builder.Configuration.AddJsonFile("appsettings.json");
builder.Services.AddControllersWithViews();
//注入服务  WebAPI访问控制
//1 携带token访问,返回了想要的数据    2 未携带token,返回401
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters()
        {
            ValidateIssuer = true,//是否验证Issuer
            ValidIssuer = builder.Configuration["Jwt:Issuer"],
            ValidateAudience = true,//是否验证Audience
            ValidAudience = builder.Configuration["Jwt:Audience"],
            ValidateLifetime = true,//是否验证失效时间
            ClockSkew = TimeSpan.FromSeconds(5),
            ValidateIssuerSigningKey = true,//是否验证SecurityKey
            IssuerSigningKey = 
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Secret"])),
        };

        options.Events = new JwtBearerEvents()
        {
            //验证是否传入token
            OnMessageReceived = context =>
            {
                context.Token = context.Request.Query["Authorization"];
                return Task.CompletedTask;
            },
            OnAuthenticationFailed = context =>
            {
                // 如果过期,则把<是否过期>添加到,返回头信息中
                if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                {
                    //context.Response.Headers.Add("Token-Expired", "true");
                    //自定义自己想要返回的数据结果,我这里要返回的是Json对象,
通过引用Newtonsoft.Json库进行转换
                    var payload = JsonConvert.SerializeObject(new { Code = "401",
 Message = "很抱歉,Token无效或已过期" });
                    //自定义返回的数据类型
                    context.Response.ContentType = "application/json";
                    //自定义返回状态码,默认为401 我这里改成 200
                    context.Response.StatusCode = StatusCodes.Status200OK;
                    //输出Json数据结果
                    context.Response.WriteAsync(payload);
                   // return Task.FromResult(0);
                }
                return Task.CompletedTask;
            }
        };
    });
var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");

    app.UseHsts();
}
app.UseAuthentication();
app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

///添加jwt验证
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

这时当我们携带token请求时会返回正确结果,反之则返回401错误提示

需要安装的SDK如下,可通过NuGet安装:

为您推荐

发表评论

您的电子邮箱地址不会被公开。