zoukankan      html  css  js  c++  java
  • ASP.NET Core系列:JWT身份认证

    1. JWT概述

      JSON Web Token(JWT)是目前流行的跨域身份验证解决方案。

      JWT的官网地址:https://jwt.io

      JWT的实现方式是将用户信息存储在客户端,服务端不进行保存。每次请求都把令牌带上以校验用户登录状态,这样服务就变成无状态的,利于服务器集群扩展。

    1.1 JWT令牌结构

      在紧凑的形式中,JSON Web Tokens由dot(.)分隔的三个部分组成:

      ◊ Header 头

      ◊ Payload 载荷

      ◊ Signature 签名

      因此,JWT通常如右所示:xxxxx.yyyyy.zzzzz

      (1)Header

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

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

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

      (2)Payload

      Payload用来存放需要传递的数据,包括用户信息及认证信息等。

      JWT 规定了7个官方字段,供选用。

      ◊ iss (issuer):签发人

      ◊ exp (expiration time):过期时间

      ◊ sub (subject):主题

      ◊ aud (audience):受众

      ◊ nbf (Not Before):生效时间

      ◊ iat (Issued At):签发时间

      ◊ jti (JWT ID):编号

      除了官方字段,可以在这个部分自定义其它字段。

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

      注意:JWT 默认是不加密的,任何人都可以读到,所以不要把秘密信息放在这个部分。

      (3)Signature

      Signature 部分是对前两部分的签名,防止数据篡改。这部分存在的意义就是为了解决前面部分的不安全性。

      首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。

    HMACSHA256( 
      base64UrlEncode(header) + "." + 
      base64UrlEncode(payload), 
      SECREATE_KEY 
    )

      签名用于验证消息在此过程中未被更改,并且,在使用私钥签名的令牌的情况下,它还可以验证JWT的发件人是否是它所声称的人。

    2. ASP.NET Core中集成JWT身份认证

      新建ASP.NET Core API应用程序,添加安装包:

    Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
    Install-Package System.IdentityModel.Tokens.Jwt

      appsettings.json

    {
      "Jwt": {
        "Issuer": "Issuer",
        "Audience": "Audience",
        "SigningKey": "EF1DA5B7-C4FA-4240-B997-7D1701BF9BE2"
      }
    }

      JwtConfig.cs

    public class JwtConfig
    {
        public string Issuer { get; set; }
    
        public string Audience { get; set; }
    
        public string SigningKey { get; set; }
    }

      Startup.cs

    using Microsoft.AspNetCore.Authentication.JwtBearer;
    using Microsoft.IdentityModel.Tokens;
    
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
    
        public IConfiguration Configuration { get; }
    
        public void ConfigureServices(IServiceCollection services)
        {
            var jwtconfig = Configuration.GetSection("Jwt").Get<JwtConfig>();
            // JWT身份认证
            services.AddAuthentication(option =>
            {
                option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(option =>
            {
                option.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidIssuer = jwtconfig.Issuer,
                    ValidAudience = jwtconfig.Audience,
                    ValidateIssuer = true,
                    ValidateLifetime = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtconfig.SigningKey)),
                    // 缓冲过期时间,总的有效时间等于这个时间加上jwt的过期时间,如果不配置,默认是5分钟
                    ClockSkew = TimeSpan.FromSeconds(3)
                };
            });
    
            services.AddOptions().Configure<JwtConfig>(Configuration.GetSection("Jwt"));
    
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }
    
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            // JWT身份认证
            app.UseAuthentication();
    
            app.UseMvc();
        }
    }

      AuthController.cs

    using System.Security.Claims;
    using Microsoft.IdentityModel.Tokens;
    using System.IdentityModel.Tokens.Jwt;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.Extensions.Options;
    
    [Route("api/[controller]")]
    [ApiController]
    public class AuthController : ControllerBase
    {
        private JwtConfig jwtconfig;
        public AuthController(IOptions<JwtConfig> option)
        {
            jwtconfig = option.Value;
        }
    
        [HttpGet]
        public ActionResult<string> Get()
        {
            var claim = new Claim[]{
                new Claim("UserName", "lb")
            };
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtconfig.SigningKey));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var token = new JwtSecurityToken(
                issuer: jwtconfig.Issuer,
                audience: jwtconfig.Audience,
                claims: claim,
                notBefore: DateTime.Now,
                expires: DateTime.Now.AddSeconds(30),
                signingCredentials: creds);
    
            return Ok(new { token = new JwtSecurityTokenHandler().WriteToken(token) });
        }
    
        /// <summary>
        /// 在需要身份认证的方法添加[Authorize]
        /// </summary>
        [Authorize]
        [HttpGet("{id}")]
        public ActionResult<string> Get(int id)
        {
            return "value";
        }
    }

      在访问需要JWT身份认证的接口时,接口添加header参数Authorization,值为“Bearer”+空格+token。若不能通过JWT身份认证,则调用接口返回状态401未认证。

  • 相关阅读:
    MyBatis 缓存机制
    MyBatis 动态SQL
    SpringMVC的简介与使用
    捕获组和前后查找
    正则表达式:( ) 小括号、[ ] 中括号、{ } 大括号的区别
    343.整数拆分
    74. 搜索二维矩阵
    数的划分
    213.打家劫舍||
    整数划分为k份
  • 原文地址:https://www.cnblogs.com/libingql/p/11384141.html
Copyright © 2011-2022 走看看