.Net Core 使用JWT权限验证


什么是JWT?

它是一种对API的保护方案(防泄漏,防攻击,防止被人篡改)

一,下载相关NuGet包

  Microsoft.AspNetCore.Authentication.JwtBearer

  dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer(下载语句)

二,创建JwtHelpers.cs(帮助类 生成Token)

  下面是JwtHelpers.cs 及注解

using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Text;
using System.IdentityModel.Tokens.Jwt;

namespace JwtAuthDemo.Helpers
{
    public class JwtHelpers
    {
        private readonly IConfiguration Configuration;

        public JwtHelpers(IConfiguration configuration)
        {
            this.Configuration = configuration;
        }
        public string GenerateToken(string userName, int expireMinutes = 30)
        {
            var issuer = Configuration.GetValue<string>("JwtSettings:Issuer");
            var signKey = Configuration.GetValue<string>("JwtSettings:SignKey");

            // 设定要加入到 JWT Token 中的声明资讯(Claims)
            var claims = new List();

            // 在 RFC 7519 规格中(Section#4),总共定义了 7 个预设的 Claims,我们应该只用的到两种!
            //claims.Add(new Claim(JwtRegisteredClaimNames.Iss, issuer));
            claims.Add(new Claim(JwtRegisteredClaimNames.Sub, userName)); // User.Identity.Name
            //claims.Add(new Claim(JwtRegisteredClaimNames.Aud, "The Audience"));
            //claims.Add(new Claim(JwtRegisteredClaimNames.Exp, DateTimeOffset.UtcNow.AddMinutes(30).ToUnixTimeSeconds().ToString()));
            //claims.Add(new Claim(JwtRegisteredClaimNames.Nbf, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString())); // 必須为數字
            //claims.Add(new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString())); // 必須为數字
            claims.Add(new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())); // JWT ID

            // 网路上常看到的这个 NameId 设定是多馀的
            //claims.Add(new Claim(JwtRegisteredClaimNames.NameId, userName));

            // 这个 Claim 也以直接被 JwtRegisteredClaimNames.Sub 取代,所以也是多馀的
            //claims.Add(new Claim(ClaimTypes.Name, userName));

            // 你可以自行扩充 "roles" 加入登入者该有的角色
            claims.Add(new Claim("roles", "Admin"));
            claims.Add(new Claim("roles", "Users"));

            var userClaimsIdentity = new ClaimsIdentity(claims);

            // 建立一组对称式加密的金钥,主要用于 JWT 签章之用
            var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(signKey));

            // HmacSha256 有要求必須要大于128bits,所以 key 不能太短,至少要16字元以上
            // https://stackoverflow.com/questions/47279947/idx10603-the-algorithm-hs256-requires-the-securitykey-keysize-to-be-greater
            var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);

            // 建立 SecurityTokenDescriptor
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Issuer = issuer,
                //Audience = issuer, // 由于你的 API 受众通常没有区分特别对象,因此通常不太需要设定,也不太需要验证//NotBefore = DateTime.Now, // 预设值就是 DateTime.Now
                //IssuedAt = DateTime.Now, // 预设值就是 DateTime.Now
                Subject = userClaimsIdentity,
                Expires = DateTime.Now.AddMinutes(expireMinutes),
                SigningCredentials = signingCredentials
            };

            // 产出所需要的 JWT securityToken 物件,并取得序列化后的 Token 结果(字串格式)
            var tokenHandler = new JwtSecurityTokenHandler();
            var securityToken = tokenHandler.CreateToken(tokenDescriptor);
            var serializeToken = tokenHandler.WriteToken(securityToken);

            return serializeToken;
        }
    }
}

三,在appsettings.json文件中写好配置

{
  "JwtSettings": {
    "Issuer": "JwtAuthDemo",
    "SignKey": "1Zl4h9703IzROikK3@uK&&OEb"
  },
}

四,在Startup.cs中配置相关内容

  1,将类注册进 .NET Core 的 DI 容器中:

services.AddSingleton();

  2,让你的 ASP.NET Core 能够认得使用者传入的 Bearer Token,这部分只要设定好即可:

services
                .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    // 当验证失败时,回应标头会包含 WWW-Authenticate 标头,这里会显示失败的详细错误原因
                    options.IncludeErrorDetails = true; // 預設值為 true,有時會特別關閉

                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        // 通过这项宣告,就可以从 "sub" 取值并设定给 User.Identity.Name
                        NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
                        // 通过这项宣告,就可以从 "roles" 取值,并可让 [Authorize] 判断角色
                        RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",

                        // 一般我们都会验证 Issuer
                        ValidateIssuer = true,
                        ValidIssuer = Configuration.GetValue<string>("JwtSettings:Issuer"),

                        // 通常不太需要验证 Audience
                        ValidateAudience = false,
                        //ValidAudience = "JwtAuthDemo", // 不验证就不需要填写

                        // 一般我们都会验证 Token 的有效期间
                        ValidateLifetime = true,

                        // 如果 Token 中包含 key 才需要验证,一般都只有签章而已
                        ValidateIssuerSigningKey = false,

                        // "1234567890123456" 应该从 IConfiguration 取得
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetValue<string>("JwtSettings:SignKey")))
                    };
                });
services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "jwtlianxi119", Version = "v1" });
                #region 开启Swagger认证
                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
                {

                    Description = "在下框中输入请求头中需要添加Jwt授权Token:Bearer Token",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.ApiKey,
                    BearerFormat = "JWT",
                    Scheme = "Bearer"
                });

                c.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference {
                                Type = ReferenceType.SecurityScheme,
                                Id = "Bearer"
                            }
                        },
                        new string[] { }
                    }
                });
                #endregion
            });

  3,在管道中设置(在 app.UseAuthorization() 之上:

app.UseAuthentication();

五,以下是 Web API 控制器的设计范例:

using System.Linq;
using JwtAuthDemo.Helpers;

using
Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace JwtAuthDemo.Controllers { [Authorize] [ApiController] public class TokenController : ControllerBase { private readonly JwtHelpers jwt; public TokenController(JwtHelpers jwt) { this.jwt = jwt; } [AllowAnonymous] [HttpPost("~/signin")] public ActionResult<string> SignIn(LoginViewModel login) { if (ValidateUser(login)) {
          //login.Username用户名  var token = jwt.GenerateToken(login.Username);
          //在请求头中加入token
          HttpContext.Response.Headers.Add("token", token);//HttpContext.Response.Headers["token"] = token;
          HttpContext.Response.Headers["Access-Control-Expose-Headers"] = "token";
          return Ok(login.Username);
} else { return BadRequest(); } }
     //登录
private bool ValidateUser(LoginViewModel login) { return true; // TODO }     
[HttpGet(
"~/claims")] public IActionResult GetClaims() { return Ok(User.Claims.Select(p => new { p.Type, p.Value })); } [HttpGet("~/username")] public IActionResult GetUserName() { return Ok(User.Identity.Name); }        [HttpGet("~/jwtid")] public IActionResult GetUniqueId() { var jti = User.Claims.FirstOrDefault(p => p.Type == "jti"); return Ok(jti.Value); } } }

注:一套连招下来  你的jwt token权限验证就配置成功了 

[AllowAnonymous]可以取消对方法的验证