在 ASP.NET Core WebAPI 中使用 JWT 驗證

栏目: ASP.NET · 发布时间: 5年前

内容简介:為了保護 WebAPI 僅提供合法的使用者存取,有很多機制可以做,透過 JWT (JSON Web Token) 便是其中一種方式,這篇示範如何使用官方所提供的順道一提,要產生 JWT Token 有很多套件可以幫助開發者快速建立,使用 Visual Studio 2019 建立 ASP.NET Core WebAPI 專案後,首先修改

為了保護 WebAPI 僅提供合法的使用者存取,有很多機制可以做,透過 JWT (JSON Web Token) 便是其中一種方式,這篇示範如何使用官方所提供的 System.IdentityModel.Tokens.Jwt 擴充套件,處理呼叫 API 的來源是否為合法的使用者身分。

順道一提,要產生 JWT Token 有很多套件可以幫助開發者快速建立, JWT 這個 NuGet 套件就是其中一個,但這裡我使用官方所提供的 System.IdentityModel.Tokens.Jwt 擴充套件來處理,雖然這是官方提供的版本,但寫起來一點也不困難。

建立專案

使用 Visual Studio 2019 建立 ASP.NET Core WebAPI 專案後,首先修改 Startup.cs 中的 ConfigureServices 方法,設定這個 WebAPI 站台要使用哪種方式來驗證 HTTP Request 是否合法,程式碼如下:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    // STEP1: 設定用哪種方式驗證 HTTP Request 是否合法
    services
        // 檢查 HTTP Header 的 Authorization 是否有 JWT Bearer Token
        .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        // 設定 JWT Bearer Token 的檢查選項
        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidIssuer = Configuration["Jwt:Issuer"],
                ValidateAudience = true,
                ValidAudience = Configuration["Jwt:Issuer"],
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
            };
        });
}

這裡我們設定系統在驗證 JWT Token 時,必須要符合以下 4 個條件:

  1. 相同的 Issuer 設定值
  2. 相同的 Audience 設定值
  3. 驗證 Token 有效期限
  4. 符合對稱式加密的簽章

接者一樣在 Startup.cs 中的 Configure 加入驗證權限用的 Middleware,讓每次進來的 HTTP Request 都會經過此層驗證機制,程式碼如下:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // 略...

    // STEP2: 使用驗證權限的 Middleware
    app.UseAuthentication();

    app.UseHttpsRedirection();
    app.UseMvc();
}

如此一來網站的基本設定就搞定了。

取得 JWT Token

要如何產生 JWT Token 呢?這裡我們建立了一個 AuthController 控制器來產生所需要的 JWT Token,流程如下:

  1. 身分驗證
  2. 建立使用者聲明資訊
  3. 取得加密金鑰
  4. 建立 JWT Token

身分驗證是你的需求自行實作,驗證後可將取得的使用者資訊(非機敏資訊)包進使用者的 Claim 聲明中,這些資訊將會是 JWT Payload 的一部分,這裡的 Claim 聲明資訊也可以根據你的需求客制增加。

我們知道 JWT 是用三部分 Header、Payload 和 Signature,並使用 (.)將三個部分連結起來成為一個字串,Signature 這部分會是 Header、Payload 加上一組 Secret 做雜湊運算產生出來的,用來驗證整個 JWT 資訊是沒有被竄改過。加密金鑰這段雖然是選用,但還是相當建議加上去,增加安全強度。

接著透過 System.IdentityModel.Tokens.Jwt 這個命名空間底下的 JwtSecurityTokenHandler 來產生 JWT Token,而 JWT Token 的內容描述則交由 SecurityTokenDescriptor 來組合,在 JWT Token 的內容描述中,請根據需求做調整。

如此一來就可以產生所需要的 JWT Token 了。

[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
    private readonly IConfiguration _config;

    public AuthController(IConfiguration configuration)
    {
        _config = configuration;
    }

    // GET api/auth/login
    [HttpGet, Route("login")]
    public IActionResult Login(string name)
    {
        // STEP0: 在產生 JWT Token 之前,可以依需求做身分驗證

        // STEP1: 建立使用者的 Claims 聲明,這會是 JWT Payload 的一部分
        var userClaims = new ClaimsIdentity(new[] {
            new Claim(JwtRegisteredClaimNames.NameId, name),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            new Claim("CustomClaim", "Anything You Like")
        });
        // STEP2: 取得對稱式加密 JWT Signature 的金鑰
        // 這部分是選用,但此範例在 Startup.cs 中有設定 ValidateIssuerSigningKey = true 所以這裡必填
        var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
        // STEP3: 建立 JWT TokenHandler 以及用於描述 JWT 的 TokenDescriptor
        var tokenHandler = new JwtSecurityTokenHandler();
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Issuer = _config["Jwt:Issuer"],
            Audience = _config["Jwt:Issuer"],
            Subject = userClaims,
            Expires = DateTime.Now.AddMinutes(30),
            SigningCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256)
        };
        // 產出所需要的 JWT Token 物件
        var securityToken = tokenHandler.CreateToken(tokenDescriptor);
        // 產出序列化的 JWT Token 字串
        var serializeToken = tokenHandler.WriteToken(securityToken);

        return new ContentResult() { Content = serializeToken };
    }
}

如何使用

使用上非常簡單,只要掛上需要的裝飾器即可,這裡建立了 ValuesController 做測試,分別掛上 [AllowAnonymous][Authorize] ,前者是給匿名登入使用,也就是不需要有 JWT Token 也能執行,後者則必須要在 HTTP 的 Authorization Header 必須設定合法的 JWT Bearer Token 才能使用。

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values/anonymous
    /// <summary>使用匿名登入,無視於身分驗證</summary>
    [AllowAnonymous]
    [HttpGet, Route("anonymous")]
    public IActionResult Anonymous()
    {
        return new ContentResult() { Content = $@"For all anonymous." };
    }

    // GET api/values/authorize
    /// <summary>使用身分驗證,HTTP 的 Authorization Header 必須設定合法的 JWT Bearer Token 才能使用</summary>
    [Authorize]
    [HttpGet, Route("authorize")]
    public IActionResult All()
    {
        return new ContentResult() { Content = $@"For all client who authorize." };
    }
}

這個驗證裝飾器還可以有很多種玩法,例如根據所建立的驗證 Policy 做驗證,或根據使用者 Claim 聲明的角色做驗證,提供了很大的彈性來處理。

JwtRegisteredClaimNames 屬性說明

在建立使用者的 Claims 聲明時,我們會用到很多 JwtRegisteredClaimNames 結構型別,來取得是先定義好的字串,在 System.IdentityModel.Tokens.Jwt 命名空間中的 JwtRegisteredClaimNames 定義了很多 JWT 會用到的聲明,但 官方文件 說明相當的少,自行整理了如下:

聲明欄位 說明 連結
Jti 表示 JWT ID,Token 的唯一識別碼 http://tools.ietf.org/html/rfc7519#section-4
Iss 表示 Issuer,發送 Token 的發行者 http://tools.ietf.org/html/rfc7519#section-4
Iat 表示 Issued At,Token 的建立時間 http://tools.ietf.org/html/rfc7519#section-4
Exp 表示 Expiration Time,Token 的逾期時間 http://tools.ietf.org/html/rfc7519#section-4
Sub 表示 Subject,Token 的主體內容 http://tools.ietf.org/html/rfc7519#section-4
Aud 表示 Audience,接收 Token 的觀眾 http://tools.ietf.org/html/rfc7519#section-4
Typ 表示 Token 的類型,例如 JWT 表示 JSON Web Token 類型 http://tools.ietf.org/html/rfc7519#section-4
Nbf 表示 Not Before,定義在什麼時間之前,不可用 http://tools.ietf.org/html/rfc7519#section-4
Actort 識別執行授權的代理是誰 http://tools.ietf.org/html/rfc7519#section-4
Prn http://tools.ietf.org/html/rfc7519#section-4
Nonce http://tools.ietf.org/html/rfc7519#section-4
NameId 使用者識別碼 http://tools.ietf.org/html/rfc7519#section-4
FamilyName 使用者姓氏 http://tools.ietf.org/html/rfc7519#section-4
GivenName 使用者名字 http://tools.ietf.org/html/rfc7519#section-4
Gender 使用者性別 http://tools.ietf.org/html/rfc7519#section-4
Email 使用者的電子郵件 http://tools.ietf.org/html/rfc7519#section-4
Birthdate 使用者生日 http://tools.ietf.org/html/rfc7519#section-4
Website 使用者的網站 http://tools.ietf.org/html/rfc7519#section-4
CHash http://tools.ietf.org/html/rfc7519#section-4
UniqueName http://tools.ietf.org/html/rfc7519#section-4
AtHash http://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken
Acr http://openid.net/specs/openid-connect-core-1_0.html#IDToken
Amr http://openid.net/specs/openid-connect-core-1_0.html#IDToken
Azp http://openid.net/specs/openid-connect-core-1_0.html#IDToken
AuthTime http://openid.net/specs/openid-connect-core-1_0.html#IDToken
Sid http://openid.net/specs/openid-connect-frontchannel-1_0.html#OPLogout

有些定義的聲明欄位很難找到說明,有找到相關資訊再陸續補充。

程式碼

關於本篇文章完整的程式碼發布於 GitHub: poychang/Demo-WebAPI-Jwt-Auth ,請參考裡面的 SimpleJwtAuth 專案。

參考資料:


以上所述就是小编给大家介绍的《在 ASP.NET Core WebAPI 中使用 JWT 驗證》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法设计与分析

算法设计与分析

张德富 / 2009-8 / 36.00元

《算法设计与分析》主要取材于算法设计与分析领域的经典内容,并介绍了算法设计的发展趋势。内容主要包括非常经典的算法设计技术,例如递归与分治、动态规划、贪心、回溯、分支限界、图算法,也包括了一些高级的算法设计主题,例如网络流和匹配、启发式搜索、线性规划、数论以及计算几何。在算法分析方面,介绍了概率分析以及最新的分摊分析和实验分析方法。在算法的理论方面,介绍了问题的下界、算法的正确性证明以及NP完全理论......一起来看看 《算法设计与分析》 这本书的介绍吧!

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

html转js在线工具
html转js在线工具

html转js在线工具