.NET CORE web api 集成jwt登录认证

一、什么是JSON Web令牌?

  JSON Web Token(JWT)是一种开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间作为JSON对象安全地传输信息。此信息可以验证和信任,因为它是经过数字签名的。JWT可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名

  虽然JWT可以被加密以在各方之间提供保密性,但我们将重点关注签名令牌。签名令牌可以验证其中包含的声明的完整性,而加密令牌会对其他方隐藏这些声明。当使用公钥/私钥对令牌进行签名时,签名还证明只有持有私钥的一方才是签名方。

二、When should you use JSON Web Tokens?

  以下是一些JSON Web标记有用的场景:

  授权:这是使用JWT最常见的场景。用户登录后,每个后续请求都将包括JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是目前广泛使用JWT的一种功能,因为它的开销很小,并且能够轻松地跨不同的域使用。

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

  什么是JSON Web令牌结构?

  在紧凑的形式中,JSON Web标记由三部分组成,由点(.)分隔,它们是:标题  有效载荷  签名

  因此,JWT通常如下所示。

  xxxxx。YYYY。zzzzz

  让我们把不同的部分分解一下。 

  标题

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

  For example:

  {
  "alg": "HS256",
  "typ": "JWT"
  }
  Then, this JSON is Base64Url encoded to form the first part of the JWT.

  有效载荷

  令牌的第二部分是有效载荷,其中包含声明。声明是关于实体(通常是用户)和其他数据的声明。索赔有三种类型:登记索赔、公开索赔和私人索赔。

   注册声明:这些声明是一组预定义的声明,不是强制性的,而是推荐的,以提供一组有用的、可互操作的声明。其中一些是:iss(发行人)、exp(到期时间)、sub(主题)、aud(观众)和其他。

  公开声明:这些声明可以由使用JWTs的人随意定义。但为了避免冲突,它们应该在IANA JSON Web令牌注册表中定义,或者定义为包含防冲突命名空间的URI。

      私人索赔:这些自定义索赔是为了在同意使用它们的各方之间共享信息而创建的,既不是注册索赔,也不是公开索赔。

  

  An example payload could be:

  {
    "sub": "1234567890",
    "name": "John Doe",
    "admin": true
  }

  The payload is then Base64Url encoded to form the second part of the JSON Web Token.

  Signature

  To create the signature part you have to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that.

  For example if you want to use the HMAC SHA256 algorithm, the signature will be created in the following way:

  签名

  要创建签名部分,您必须获取编码的报头、编码的有效负载、一个秘密、报头中指定的算法,并对其进行签名。 

  例如,如果要使用HMAC SHA256算法,则将按以下方式创建签名:

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

  签名用于验证消息在发送过程中没有发生更改,如果是使用私钥签名的令牌,它还可以验证JWT的发送者是它所说的人。

  综合起来

  输出是三个由点分隔的Base64 URL字符串,可以在HTML和HTTP环境中轻松传递,同时与基于XML的标准(如SAML)相比更加紧凑。 

  下面显示了一个JWT,它对前一个头和有效负载进行了编码,并用一个秘密进行了签名。

 

 

 

  如果您想使用JWT并将这些概念付诸实践,可以使用JWT.io,用于解码、验证和生成JWT

三、JSON Web令牌是如何工作的?

  在身份验证中,当用户使用其凭据成功登录时,将返回一个JSON Web令牌。由于令牌是凭证,因此必须非常小心地防止安全问题。一般来说,您不应该将代币保存的时间超过所需时间。由于缺乏安全性,您也不应该在浏览器存储中存储敏感会话数据。 每当用户想要访问受保护的路由或资源时,用户代理都应该发送JWT,通常在使用承载模式的授权报头中。标题的内容应如下所示:

  

Authorization: Bearer <token>

  在某些情况下,这可能是一种无状态授权机制。服务器的受保护路由将在授权头中检查有效的JWT,如果存在,则允许用户访问受保护的资源。如果JWT包含必要的数据,可能会减少查询数据库中某些操作的需要,尽管情况并非总是如此。请注意,如果通过HTTP头发送JWT令牌,则应尽量防止它们变得太大。有些服务器不接受超过8KB的头文件。如果您试图在JWT令牌中嵌入太多信息,比如通过包含所有用户的权限,那么您可能需要另一种解决方案,比如Auth0细粒度授权。如果令牌在授权头中发送,则跨源资源共享(CORS)不会成为问题,因为它不使用cookie。

  下图显示了如何获取JWT并使用其访问API或资源:

   

 

     请注意,对于签名令牌,令牌中包含的所有信息都会暴露给用户或其他方,即使他们无法更改。这意味着您不应该将机密信息放入令牌中。

 

四、.NET CORE  添加jwt认证

1、新建jwt参数类

    public class TokenConfig
    {

        /// <summary>
        /// 密钥
        /// </summary>
        public static string secret = "9999999999999999999999999";
        /// <summary>
        /// 签发者
        /// </summary>
        public static  string issuer = "yinmingneng";
        /// <summary>
        /// 受众
        /// </summary>
        public static  string audience = "ymn";
        /// <summary>
        /// 令牌过期时间
        /// </summary>
        public static  int accessExpiration = 20;
    }

二、身份认证设置成jwt认证,

uilder.Services.AddAuthentication(options => {
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x => { 
    x.RequireHttpsMetadata= false;
    x.SaveToken = true;
    x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters {
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(TokenConfig.secret)),
        ValidIssuer = TokenConfig.issuer,
        ValidAudience = TokenConfig.audience,
        ValidateIssuer = false,
        ValidateAudience = false
    };
    x.Events = new JwtBearerEvents()
    {
        OnMessageReceived = context =>
        {
            context.Token = context.Request.Query["access_token"];
            return Task.CompletedTask;
        },
        OnAuthenticationFailed = context =>
        {
            // 如果过期,则把<是否过期>添加到,返回头信息中
            if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
            {
                context.Response.Headers.Add("Token-Expired", "true");
            }
            return Task.CompletedTask;
        }
    };

});

三、新建一个控制器,用于模拟登录,返回Token

 public class Authorization : Controller
    {

        [HttpGet("GetToken")]
        public string GetToken() {
            //载荷增加用户
            var claims = new[] {
             new    Claim(ClaimTypes.Name,"yinmingneng"),
             new Claim(ClaimTypes.Email,"123@qq.com")
            };
            //加密密钥
            var key = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(TokenConfig.secret));
            ///签名
            var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var jwttoken = new JwtSecurityToken(TokenConfig.issuer,TokenConfig.audience, claims, DateTime.Now
                ,DateTime.Now.AddMinutes(TokenConfig.accessExpiration),credentials);
            var token =  new JwtSecurityTokenHandler().WriteToken(jwttoken);
            return token;
        }
        
    }

 

四、测试Token,新建一个控制器,控制器上增加[Authorize]权限认证,增加表示必须携带Token才能访问

    [ApiController]
    [Route("[controller]")]
    [Authorize]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

        private readonly ILogger<WeatherForecastController> _logger;
        public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }
        [HttpGet(Name = "GetWeatherForecast")]
        public IEnumerable<WeatherForecast> Get()
        {
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }

五、测试、获取Token访问方法

 

 

 

使用Token,访问,如果不携带会提示无权限访问,比如

 

 

 

携带Token访问,

 

 

 

 

posted on 2022-03-12 22:21  topguntopgun  阅读(1736)  评论(1编辑  收藏  举报

导航