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

2. 有效載荷

JWT的有效負(fù)載部分包含了我們希望在兩個(gè)通信方之間傳遞的關(guān)于某個(gè)實(shí)體的實(shí)際數(shù)據(jù)或聲明信息。有效負(fù)載通常包含用戶數(shù)據(jù):

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

3. 簽名

最后,簽名用于驗(yàn)證 JWT 是否未被更改或操縱。它通過使用標(biāo)頭中指定的算法對編碼的標(biāo)頭、有效負(fù)載和密鑰進(jìn)行簽名來實(shí)現(xiàn)此目的。如果JWT中的數(shù)據(jù)被更改,服務(wù)器在檢測時(shí)會(huì)發(fā)現(xiàn)這一變化并拒絕接受。

授權(quán)流程

JWT的防篡改特性使其成為雙方之間安全交換信息的優(yōu)選方案。由于令牌已經(jīng)過簽名,我們可以確認(rèn)發(fā)件人的身份,并檢查令牌中的數(shù)據(jù)是否已被更改。

使用 JWT 的典型授權(quán)流如下所示:

在 .NET API 中設(shè)置 JWT 授權(quán)

設(shè)置 Json Web 令牌身份驗(yàn)證可以相當(dāng)簡單地完成。讓我們看一個(gè)例子。

  1. 安裝必要的軟件包

Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
Install-Package Microsoft.IdentityModel.Tokens
Install-Package Microsoft.IdentityModel.JsonWebTokens

2. 在 Program.cs 中配置 Json Web Token 鑒權(quán)服務(wù)。

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

var key = "this is my custom Secret key for authentication"; // This should be stored securely, e.g., in environment variables

builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key))
};
});

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

首先,我們定義一個(gè)將用于令牌簽名的密鑰。

注意:為了確保密鑰的安全,應(yīng)當(dāng)將其妥善存儲(chǔ)。雖然在此處為了演示方便以純文本形式展示,但在實(shí)際生產(chǎn)應(yīng)用程序中,必須確保密鑰的安全存儲(chǔ)與訪問。例如通過環(huán)境變量或 Secret Management 服務(wù)。

然后,我們配置身份驗(yàn)證服務(wù),并指明希望使用JSON Web Token(JWT)。我們設(shè)置為驗(yàn)證令牌是否使用了正確的密鑰進(jìn)行簽名(validate_issuer_signing_key: true)。這一步驟至關(guān)重要,因?yàn)樗艽_保令牌未被篡改,且確實(shí)來自一個(gè)受信任的來源。最后,我們使用之前定義的密鑰(secret key)來指定簽名的密鑰。

3.為Login Endpoint創(chuàng)建一個(gè)控制器,使用System.IdentityModel.Tokens.Jwt命名空間。

using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;

namespace JsonWebTokens.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
private readonly string _key;

public AuthController(IConfiguration config)
{
_key = "this is my custom Secret key for authentication";
}

[HttpPost("login")]
public IActionResult Login([FromBody] UserLogin userLogin)
{
if (userLogin.Username == "test" && userLogin.Password == "password")
{
var token = GenerateJwtToken(userLogin.Username);
return Ok(new { token });
}

return Unauthorized();
}

private string GenerateJwtToken(string username)
{
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, username),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
};

var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_key));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

var token = new JwtSecurityToken(
issuer: null,
audience: null,
claims: claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: creds);

return new JwtSecurityTokenHandler().WriteToken(token);
}
}

public class UserLogin
{
public string Username { get; set; }
public string Password { get; set; }
}
}

在此示例中,一個(gè)簡單的 POST 終端節(jié)點(diǎn)接受正文中的對象。然后,我們檢查提供的憑證是否與預(yù)期匹配。在實(shí)際的 UserLogin生產(chǎn)應(yīng)用程序中,您通常會(huì)從數(shù)據(jù)庫中讀取用戶,并根據(jù)數(shù)據(jù)庫中存儲(chǔ)的哈希版本檢查提供的密碼。若憑證驗(yàn)證通過,我們將生成一個(gè)令牌,并將其返回給客戶端。該令牌的有效負(fù)載中會(huì)包含用戶名信息,并且設(shè)置其過期時(shí)間為30分鐘。

4. 使用授權(quán)保護(hù)端點(diǎn)

現(xiàn)在,我們可以繼續(xù)為要保護(hù)的端點(diǎn)添加授權(quán):

[Route("api/[controller]")]
[ApiController]
public class WeatherForecastController : ControllerBase
{
[HttpGet]
[Authorize]
public IActionResult Get()
{
return Ok(new { message = "This is a protected endpoint" });
}
}

我們使用屬性(attribute)來修飾那些我們希望進(jìn)行保護(hù)的controller,以此指示這些controller應(yīng)使用我們之前定義的認(rèn)證配置。如果請求中未提供有效的令牌,用戶將被拒絕訪問,并收到401狀態(tài)碼(未授權(quán))。具體做法是在controller類上添加[Authorize]屬性。

JSON Web Token(JWT)特別適用于需要精細(xì)控制授權(quán)機(jī)制的場景。通過令牌的有效負(fù)載,我們可以提取與用戶相關(guān)的信息,并據(jù)此限制對某些資源的訪問,因此,它成為了一種理想且極為流行的授權(quán)技術(shù)。

2. OAuth 2.0

什么是 OAuth 2.0?

OAuth 2.0 是一種開放標(biāo)準(zhǔn),旨在允許應(yīng)用程序代表用戶安全訪問托管在第三方服務(wù)上的服務(wù)或資源。它得到了廣泛的應(yīng)用,幾乎可以被視為在線授權(quán)的行業(yè)標(biāo)準(zhǔn)。OAuth 2.0 定義了多種流程或“方案”,用于指導(dǎo)在不同場景下如何處理授權(quán)問題。這些流也稱為授權(quán)類型,并指示應(yīng)如何針對各種情況處理授權(quán)。

OAuth 2.0 只是一個(gè)授權(quán)協(xié)議,不處理用戶身份驗(yàn)證。它旨在提供對某些資源的訪問,并使用訪問令牌來實(shí)現(xiàn)此目的。在此類場景中,JWT(JSON Web Token)是最常被采用的方式。因此,JWT 和 OAuth 2.0 并不是兩種截然不同的、互斥的技術(shù)。相反,JWT 是一種可以在 OAuth 2.0 流程中集成和使用的格式。

角色

OAuth 2.0 中的角色是指 OAuth 系統(tǒng)的不同組件。了解這些很重要。

使用客戶端憑據(jù)授予進(jìn)行授權(quán)

如上所述,OAuth 2.0 提供了不同的授權(quán)類型或流程來處理各種授權(quán)情況。其中一種授權(quán)類型是 Client Credentials Grant,我們將在本文中重點(diǎn)介紹。此流程適用于機(jī)器對機(jī)器(M2M)通信,其中不涉及用戶的直接參與。這是一種非常普遍的方法,您可能已經(jīng)在各種場景中遇到過類似的應(yīng)用。在客戶端憑證授予方案中,客戶端代表自己行事,這意味著客戶端本身需要訪問特定資源。例如,這可能是需要訪問外部 API(資源服務(wù)器)以獲取數(shù)據(jù)以進(jìn)行內(nèi)部處理的后端應(yīng)用程序(客戶端)。

客戶端憑據(jù)授權(quán)非常常見,也許是最簡單的授權(quán)類型。典型的流程如下所示:

  1. 客戶端身份驗(yàn)證: 后端應(yīng)用程序(客戶端)具有其客戶端 ID 和客戶端密鑰,用于向授權(quán)服務(wù)器進(jìn)行身份驗(yàn)證。
  2. Access Token 請求: 后端應(yīng)用程序?qū)?POST 請求發(fā)送到授權(quán)服務(wù)器的令牌終端節(jié)點(diǎn),其中包含其客戶端 ID、客戶端密鑰和授權(quán)類型。
  3. 訪問令牌響應(yīng): 授權(quán)服務(wù)器驗(yàn)證客戶端的憑證,并使用訪問令牌進(jìn)行響應(yīng)。
  4. 資源請求:后端應(yīng)用程序使用訪問令牌從外部 API(資源服務(wù)器)請求數(shù)據(jù)。
  5. 資源響應(yīng):資源服務(wù)器驗(yàn)證訪問令牌并使用請求的數(shù)據(jù)進(jìn)行響應(yīng)。

示例

在這個(gè)小型 .NET 示例中,我們將創(chuàng)建一個(gè)同時(shí)充當(dāng)授權(quán)服務(wù)器和資源服務(wù)器的應(yīng)用程序。通常,這兩個(gè)實(shí)體是分開的,但對于規(guī)模較小且集成度更高的應(yīng)用程序,組合方法可能非常有效,并且會(huì)降低復(fù)雜性和延遲。在決定采用哪種方法時(shí),請根據(jù)您的具體情況,在組合方法與分離方法之間做出權(quán)衡。

  1. 和以前一樣,我們首先安裝必要的軟件包。

Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
Install-Package Microsoft.IdentityModel.Tokens
Install-Package Microsoft.IdentityModel.JsonWebTokens

2. 再次在 Program.cs 中創(chuàng)建必要的 JWT 配置

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

var key = "this is my custom Secret key for authentication"; // This should be stored securely, e.g., in environment variables

builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "https://localhost:7232",
ValidAudience = "https://localhost:7232",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key))
};
});

builder.Services.AddAuthorization();
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

在這個(gè)方案中,我們啟用了ValidateIssuerValidateAudience選項(xiàng)。這通過確保我們的應(yīng)用程序?qū)㈩C發(fā)者和接收者(受眾)的信息編碼到令牌中,為我們的令牌增加了額外的安全層級(jí)。通過驗(yàn)證發(fā)行者和受眾,我們能夠使得潛在攻擊者更難濫用被盜的令牌。在您事先了解將與您的應(yīng)用程序進(jìn)行交互的特定應(yīng)用程序的情況下,這一步驟尤為重要。

3. 創(chuàng)建 Token 終端節(jié)點(diǎn)。

using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;

namespace OAuth2._0.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class TokenController : ControllerBase
{
private const string ClientId = "1";
private const string ClientSecret = "secret";
private const string Issuer = "https://localhost:7232";
private const string Audience = "https://localhost:7232";
private const string Key = "this is my custom Secret key for authentication";

[HttpPost("token")]
public IActionResult Token([FromForm] string client_id, [FromForm] string client_secret)
{
if (client_id == ClientId && client_secret == ClientSecret)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(Key);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[] { new Claim("sub", client_id) }),
Expires = DateTime.UtcNow.AddHours(1),
Issuer = Issuer,
Audience = Audience,
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),
SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);

return Ok(new
{
access_token = tokenString,
token_type = "Bearer",
expires_in = 3600, // 1 hour in seconds
});
}

return BadRequest("Invalid client credentials");
}
}
}

在生產(chǎn)應(yīng)用程序中,通常會(huì)有一個(gè)底層系統(tǒng)存儲(chǔ) Client ID 和 Client Secret。隨后,這兩個(gè)值(指發(fā)行者和受眾的標(biāo)識(shí)符)將被授予那些希望訪問資源的可信系統(tǒng)(即客戶端)。在這個(gè)簡單的示例中,我們直接對這兩個(gè)值進(jìn)行了硬編碼,但請注意,在實(shí)際的生產(chǎn)應(yīng)用程序中,應(yīng)該采用更為妥善的方式來處理這些值。

我們在請求中接收client_idclient_secret,并校驗(yàn)這兩個(gè)值是否與我們的預(yù)期相匹配。如果校驗(yàn)通過,我們將繼續(xù)生成JWT令牌,并向其中添加必要的聲明信息。特別地,在這個(gè)場景下,我們會(huì)添加Issuer(發(fā)行者)和Audience(受眾)聲明。這里提到的multipart/form-data通常指的是請求的內(nèi)容類型,它允許我們以表單格式提交數(shù)據(jù),包括client_idclient_secret等信息。

響應(yīng)將按以下格式返回給客戶端:

{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwibmJmIjoxNzIzMDE4MDM5LCJleHAiOjE3MjMwMjE2MzksImlhdCI6MTcyMzAxODAzOSwiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3Q6NzIzMiIsImF1ZCI6Imh0dHBzOi8vbG9jYWxob3N0OjcyMzIifQ.0HpnhsU-Ud2zO8owCHeK5xcSIDJzU4OTLmi0LsifMx0",
"token_type": "Bearer",
"expires_in": 3600
}

在這里,我們可以看到授權(quán)服務(wù)器已向我們(客戶端)頒發(fā)了一個(gè) Bearer 令牌,該令牌將在一小時(shí)后過期。

4. 現(xiàn)在可以使用 Token Access 受保護(hù)的資源。

 [Route("api/[controller]")]
[ApiController]
public class ResourceController : ControllerBase
{
[HttpGet]
[Authorize]
public IActionResult Get()
{
return Ok("Protected resource data");
}
}

用法

OAuth 2.0 是一個(gè)行業(yè)標(biāo)準(zhǔn)框架,用于處理各種場景中的授權(quán)。在上面的簡單示例中,我們已經(jīng)演示了如何在典型的機(jī)器對機(jī)器場景中處理授權(quán),但這只是眾多用例之一。OAuth 2.0 可用于多種環(huán)境,包括 Web 應(yīng)用程序、移動(dòng)應(yīng)用程序和 IoT 設(shè)備,無論平臺(tái)如何,都可以提供統(tǒng)一的授權(quán)方法。OAuth 2.0因其有據(jù)可查且被廣泛應(yīng)用,為開發(fā)人員提供了更便捷的實(shí)現(xiàn)途徑。此外,還有眾多針對不同編程語言的工具和庫可供使用,這些工具和庫能夠簡化OAuth 2.0的集成流程。

3. 基本身份驗(yàn)證

什么是基本身份驗(yàn)證?

在前兩章中,我們了解了一些更復(fù)雜且可擴(kuò)展的授權(quán)機(jī)制。對于那些沒有相同級(jí)別伸縮性和靈活性需求的小型應(yīng)用程序而言,基本身份驗(yàn)證提供了一種更為簡單直接的方法來實(shí)施對Web資源的訪問控制,盡管它在安全性和可擴(kuò)展性方面相對較弱。

基本身份驗(yàn)證內(nèi)置于 HTTP 規(guī)范中,它允許客戶端通過發(fā)送以特定格式編碼的用戶名和密碼來向服務(wù)器驗(yàn)證自身。

基本身份驗(yàn)證的工作原理

使用基本身份驗(yàn)證的典型流程如下所示。

  1. 客戶端響應(yīng):然后,客戶端發(fā)送一個(gè)請求,其中包含編碼為 base64 的憑據(jù)(用戶名和密碼)。
  2. 服務(wù)器驗(yàn)證:服務(wù)器解碼 base64 字符串以檢索用戶名和密碼,然后驗(yàn)證這些憑據(jù)。
  3. Access Granted/Denied:如果憑證有效,則服務(wù)器將授予對所請求資源的訪問權(quán)限。否則,服務(wù)器將響應(yīng) 401 unauthorized。

其基本思路是:用戶每次向資源服務(wù)器發(fā)送請求時(shí),都會(huì)以特定方式攜帶用戶名和密碼。服務(wù)器接收到請求后,會(huì)先對這些憑據(jù)進(jìn)行解碼,然后驗(yàn)證其有效性,最終決定是否允許客戶端訪問相應(yīng)的資源。

這是一個(gè)非常簡單的解決方案,但應(yīng)謹(jǐn)慎使用,因?yàn)樗嬖谝恍﹪?yán)重的安全風(fēng)險(xiǎn)。Base64編碼僅僅是一種簡單的編碼方式,它可以很容易地被解碼,這意味著通過Base64編碼傳輸?shù)膽{據(jù)實(shí)際上是以一種近乎純文本的形式被發(fā)送的。

如果您決定使用此方法,請始終確保使用 HTTPS 通過網(wǎng)絡(luò)加密憑據(jù)。

示例

1. 我們首先創(chuàng)建一個(gè)身份驗(yàn)證處理程序

using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Text.Encodings.Web;

public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
public BasicAuthenticationHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock)
: base(options, logger, encoder, clock)
{
}

protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Headers.ContainsKey("Authorization"))
{
return AuthenticateResult.Fail("Missing Authorization Header");
}

try
{
var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
var credentials = Encoding.UTF8.GetString(credentialBytes).Split(':');
var username = credentials[0];
var password = credentials[1];

// Validate the username and password (this is just an example, you should validate against a user store)
if (username == "admin" && password == "password")
{
var claims = new[] {
new Claim(ClaimTypes.Name, username)
};
var identity = new ClaimsIdentity(claims, Scheme.Name);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, Scheme.Name);

return AuthenticateResult.Success(ticket);
}
else
{
return AuthenticateResult.Fail("Invalid Username or Password");
}
}
catch
{
return AuthenticateResult.Fail("Invalid Authorization Header");
}
}
}

這種方法相當(dāng)直接明了。此處理程序?qū)L試提取 Authorization 標(biāo)頭。如果未設(shè)置 authorization 標(biāo)頭,則拒絕訪問。然后,我們嘗試從標(biāo)頭中獲取 base64 字符串,并提取用戶名和密碼。同樣,我們只需根據(jù)硬編碼值驗(yàn)證憑證以進(jìn)行說明。通常,您會(huì)針對某些用戶存儲(chǔ)進(jìn)行檢查。

如果所有步驟都順利完成,我們將構(gòu)建一個(gè)包含必要信息的簡單聲明,并標(biāo)志著身份驗(yàn)證的成功完成。

2. 在 Program.cs 中注冊處理程序

using BasicAuth.Handlers;
using Microsoft.AspNetCore.Authentication;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddAuthentication("BasicAuthentication")
.AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthentication", null);

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

在這里,我們將應(yīng)用程序配置為使用基本身份驗(yàn)證方案,并指定我們的處理程序。

3. 我們現(xiàn)在可以保護(hù)我們的端點(diǎn)

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
[HttpGet]
[Authorize]
public IActionResult Get()
{
return Ok("Protected resource data");
}
}

用法

如上所述,基本身份驗(yàn)證提供了一種非常簡單的方法,用于對應(yīng)用程序的請求進(jìn)行身份驗(yàn)證。但是,由于其明顯的缺點(diǎn),此方法絕不應(yīng)用于促進(jìn)生產(chǎn)環(huán)境中的實(shí)際訪問控制。

在過去,我曾在安全性和可伸縮性不是首要考慮因素的簡單場景中,使用基本身份驗(yàn)證來提供對測試環(huán)境的訪問。雖然基本身份驗(yàn)證快速且易于實(shí)施,但它的使用應(yīng)當(dāng)十分謹(jǐn)慎,并且僅當(dāng)確實(shí)適合特定情況時(shí)才采用。在決定使用之前,請務(wù)必考慮其他身份驗(yàn)證方法是否更能滿足您的具體需求。

4. API Key 授權(quán)

什么是 API Key 授權(quán)?

API 密鑰授權(quán)是一種簡單且廣泛使用的方法,用于控制對 API 的訪問。這種方法非常適合于需要授予對一個(gè)或多個(gè)終端節(jié)點(diǎn)的訪問權(quán)限,但無需對用戶的具體身份進(jìn)行細(xì)致管理的場景。當(dāng)您需要訪問受限 API 時(shí)(通常是在注冊 API 之后),通常會(huì)采用此方法。注冊后,通常會(huì)向客戶端頒發(fā)一個(gè) API 密鑰,然后可以存儲(chǔ)該密鑰并用于訪問特定資源。頒發(fā)實(shí)體具備根據(jù)實(shí)際需求撤銷API密鑰并使其失效的能力。

從本質(zhì)上來說,API密鑰是一個(gè)分配給客戶端的唯一標(biāo)識(shí)符。客戶端會(huì)在其API請求中包含這個(gè)密鑰,以此獲取對服務(wù)的訪問權(quán)限。通常,API密鑰會(huì)以x-api-key的形式作為請求頭發(fā)送到服務(wù)器,服務(wù)器則會(huì)通過自定義的邏輯來提取并驗(yàn)證這個(gè)密鑰。

API密鑰的優(yōu)勢在于為開發(fā)人員提供了在實(shí)施授權(quán)邏輯時(shí)的極大靈活性。一般情況下,客戶端的信息會(huì)與它們各自的API密鑰以及其他相關(guān)的信息一同存儲(chǔ)在數(shù)據(jù)庫中。例如,您可以存儲(chǔ)客戶端的 IP 地址并驗(yàn)證請求是否來自預(yù)期的客戶端。或者,您也可以在一段時(shí)間后使 API 密鑰失效。

關(guān)鍵在于,開發(fā)人員可以自由地配置所有與授權(quán)相關(guān)的業(yè)務(wù)邏輯,這些邏輯可以根據(jù)實(shí)際需求既復(fù)雜又精細(xì),也可以相對簡單直接。這使得 API 密鑰授權(quán)成為許多需要簡單性和靈活性的應(yīng)用程序的不錯(cuò)選擇,而不是更復(fù)雜的授權(quán)方法。

API 密鑰授權(quán)的工作原理

典型的 API 密鑰授權(quán)流程如下所示:

如上所述,服務(wù)器驗(yàn)證步驟可以根據(jù)開發(fā)人員的選擇來實(shí)現(xiàn)。

示例

在API請求的處理流程中,客戶端發(fā)送的API密鑰通常會(huì)被一個(gè)中間件所捕獲。這個(gè)中間件會(huì)負(fù)責(zé)攔截API調(diào)用,并在此基礎(chǔ)上執(zhí)行相應(yīng)的授權(quán)邏輯。

  1. 我們首先創(chuàng)建授權(quán)中間件。
public class ApiKeyMiddleware
{
private readonly RequestDelegate _next;
private const string API_KEY_HEADER_NAME = "X-Api-Key";

public ApiKeyMiddleware(RequestDelegate next)
{
_next = next;
}

public async Task InvokeAsync(HttpContext context)
{
if (!context.Request.Headers.TryGetValue(API_KEY_HEADER_NAME, out var extractedApiKey))
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("API Key is missing.");
return;
}

var apiKey = "SuperSecret"; // Will normally come from a store/configuration/database

if (!apiKey.Equals(extractedApiKey))
{
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Unauthorized client.");
return;
}

await _next(context);
}
}

在這里,我們首先注入 RequestDelegate,如果一切順利,我們使用它來在 HTTP 請求管道中繼續(xù)發(fā)送請求,或者在授權(quán)失敗時(shí)終止請求。

然后,我們嘗試從相應(yīng)的標(biāo)頭中提取 API 密鑰,并根據(jù)預(yù)期的 API 密鑰對其進(jìn)行檢查。同樣地,API密鑰的存儲(chǔ)通常需要采取某種形式的安全措施,然而在這個(gè)簡單的示例中,為了演示目的,我們僅對其進(jìn)行了硬編碼處理。

如果鍵不匹配,則返回 401。如果一切正常,我們調(diào)用 _next 將請求發(fā)送到請求管道中的下一個(gè)中間件。

2. 在 Program.cs 中注冊中間件

using APIKey.Middleware;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

app.UseMiddleware<ApiKeyMiddleware>();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseRouting();
app.MapControllers();

app.Run();

就這樣。對于 API 收到的每個(gè)請求,中間件將提取 API 密鑰并確保其有效,然后允許請求繼續(xù)沿請求管道進(jìn)行。

用法

正如前面所提到的,當(dāng)我們需要為某個(gè)客戶端頒發(fā)密鑰,同時(shí)又不需要特別精細(xì)的身份管理時(shí),采用API密鑰授權(quán)無疑是一個(gè)很好的選擇。這適用于機(jī)器對機(jī)器通信,并且可以擴(kuò)展以適應(yīng)特定的用例。在上面的示例中,我們研究了最簡單的解決方案,但授權(quán)機(jī)制可以根據(jù)您的需要進(jìn)行配置。與基本身份驗(yàn)證相比較,API密鑰授權(quán)的一個(gè)顯著優(yōu)勢在于我們無需將敏感憑證直接存儲(chǔ)在實(shí)際使用的令牌(即API密鑰)中,這一特性使得它成為了一種更為安全的授權(quán)處理方式。

總結(jié)

在本文中,我們研究了在 .NET API 中處理授權(quán)的四種常用方法,每種方法都有自己的優(yōu)點(diǎn)和缺點(diǎn)。我們討論了 JWT(JSON Web 令牌)、OAuth、基本身份驗(yàn)證和 API 密鑰授權(quán)。深入理解這些方法對于選擇出最符合特定應(yīng)用需求的方法至關(guān)重要。

授權(quán)機(jī)制可能會(huì)讓人感到難以捉摸,但本文旨在為您提供一個(gè)清晰易懂、易于入門的起點(diǎn)。

原文鏈接:https://medium.com/@aschultzme/4-authorization-methods-for-securing-your-net-api-0075f2cf755b?source=search_post

上一篇:

改變醫(yī)療保健:為醫(yī)療行業(yè)構(gòu)建一個(gè)API市場

下一篇:

在Go上構(gòu)建RESTful API: Fiber, PostgreSQL, JWT和Swagge文檔
#你可能也喜歡這些API文章!

我們有何不同?

API服務(wù)商零注冊

多API并行試用

數(shù)據(jù)驅(qū)動(dòng)選型,提升決策效率

查看全部API→
??

熱門場景實(shí)測,選對API

#AI文本生成大模型API

對比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力

25個(gè)渠道
一鍵對比試用API 限時(shí)免費(fèi)

#AI深度推理大模型API

對比大模型API的邏輯推理準(zhǔn)確性、分析深度、可視化建議合理性

10個(gè)渠道
一鍵對比試用API 限時(shí)免費(fèi)