如何在.Net Core 中使用身份验证与授权(JWT)

首先我们要了解什么是JWT:JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的

在.Net Core中使用

我们先要在项目的NutGet中下载 Microsoft.AspNetCore.Authentication.JwtBearer 包(版本要与现使用的 .Net 版本一致)

我们在项目中创建一个类(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<Claim>();

          // 在 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 有要求必須要大於 128 bits,所以 key 不能太短,至少要 16 字元以上
          // https://*.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"
}

如何在.Net Core 中使用身份验证与授权(JWT)

 

Startup.cs管道中注入

//通过AddSingleton注入JwtHelpers
          services.AddSingleton<JwtHelpers>();
//验证
          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")))
              };
          });

在ConfigureServices方法中开启Swagger认证

如何在.Net Core 中使用身份验证与授权(JWT)

 

#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

在Configure方法中需要写入

//验证
          app.UseAuthentication();
          //授权
          app.UseAuthorization();

如何在.Net Core 中使用身份验证与授权(JWT)

 

我们在控制器中写入测试方法

如何在.Net Core 中使用身份验证与授权(JWT)

 

当我们登录成功后需要进行Swagger认证

如何在.Net Core 中使用身份验证与授权(JWT)

 

Value中写入Bearer +登录成功的token中

如何在.Net Core 中使用身份验证与授权(JWT)

 

完成解锁

此方式也可以获取登录的用户名,获取载荷信息,获取ID

上一篇:XCTF练习题---MISC---hong


下一篇:Authentication and authorization (three)