在 WebApi 中优先配置多个备用身份验证选项
Configuring multiple alternate authentication options with precedence in WebApi
我不清楚如何优先实现多个备用身份验证选项 -
我可以单独实现成功
- OAuth(单点登录)
- API 密钥身份验证(作为 header 传递)
我不清楚的地方 - 如何配置它以便在 API 键 header 存在且 API 键有效时处理请求;也就是说,如果您有一个有效的 API-Key,则不需要 SSO。
如果没有显示 API-Key,那么您应该期望通过 SSO。
默认应该是 SSO - 因此我在 Program.cs
中配置了以下内容
builder.Services
.AddAuthentication(
options =>
{
// If an authentication cookie is present, use it to get authentication information
options.DefaultAuthenticateScheme =
CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
// If authentication is required, and no cookie is present,
// use OAuth to sign in
options.DefaultChallengeScheme = "OAuth";
}
)
.AddCookie(
options =>
{
options.AccessDeniedPath = "/accessdenied";
}
)
.AddOAuth(
"OAuth",
(OAuthOptions options) =>
{
// abstracted out but takes care of claims, etc...
WebApp.Utils.OAuthHelper.Process(options, OAuthConfig);
}
);
但我的问题是 - 我该如何配置它来说明 - 如果 API 密钥 Header 存在,请不要理会 OAuth。
AuthenticationSchemeOptions
class has ForwardDefaultSelector
that allows any AuthenticationHandler
将身份验证事件转发给另一个处理程序。
因此,如果 API 密钥 header 不在 HTTP [=31] 中,那么您可以将 ApiKeyAuthenticationHandler
设置为默认值并使其将身份验证事件转发给 OAuth 处理程序=]s.
例如:假设您实现 ApiKeyAuthenticationHandler 如下:
// API Key options
public class ApiKeyAuthenticationOptions : AuthenticationSchemeOptions
{
public string ApiKeyHeaderName { get; set; } = "X-MY-API-KEY";
// Add more options here if needed
}
// API Key Authentication handler
public class ApiKeyAuthenticationHandler : AuthenticationHandler<ApiKeyAuthenticationOptions>
{
// Inject any additional services needed by your key handler here
public ApiKeyAuthenticationHandler(IOptionsMonitor<ApiKeyAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
{
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
// Validation logic here
// Check if the header exists
if (!Context.Request.Headers.TryGetValue(Options.ApiKeyHeaderName, out var headerValues))
{
// Header is not present fail
return AuthenticateResult.Fail("Invalid API key.");
}
// Header is present validate user
var user = await GetApiKeyUserAsync(headerValues.First());
if (user == null)
{
return AuthenticateResult.Fail("Invalid API key.");
}
// API Key is valid, generate a ClaimIdentity and Principal for the authenticated user
var identity = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, user)
}, Scheme.Name);
var principal = new ClaimsPrincipal(identity);
return AuthenticateResult.Success(new AuthenticationTicket(principal, null, Scheme.Name));
}
// Key validation logic here and you can map an API key to a user
private async Task<string?> GetApiKeyUserAsync(string key)
{
// Add your implementation here
if (key == "Alice's Key")
{
return "Alice";
}
if (key == "Bob's Key")
{
return "Bob";
}
return null;
}
}
现在在启动 class 中调用 AddAuthentication
并将 "ApiKey"
设置为默认值,并添加一个选择器函数来检查 HTTP Headers 是否存在密钥,如果密钥存在,则 return null
并让 Api 密钥处理程序处理身份验证,否则转发到“OAuth”。
builder.Services
.AddAuthentication(
options =>
{
options.DefaultAuthenticateScheme =
"ApiKey";
}
)
.AddScheme<ApiKeyAuthenticationOptions, ApiKeyAuthenticationHandler>("ApiKey", apiKeyOptions =>
{
// This scheme will forward Authentication to OAUTH if API Key header is not present
apiKeyOptions.ForwardDefaultSelector = (context) =>
{
// Check the HTTP Request for the presence of Header
if (!context.Request.Headers.TryGetValue(apiKeyOptions.ApiKeyHeaderName, out var headerValues))
{
// Header is not present, forward to OAuth
return "OAuth"; // "OAuth" is the scheme name you specified when you called "AddOAuth()
}
// Do not forward the authentication
return null;
};
})
// Add other schemes here
我不清楚如何优先实现多个备用身份验证选项 -
我可以单独实现成功
- OAuth(单点登录)
- API 密钥身份验证(作为 header 传递)
我不清楚的地方 - 如何配置它以便在 API 键 header 存在且 API 键有效时处理请求;也就是说,如果您有一个有效的 API-Key,则不需要 SSO。 如果没有显示 API-Key,那么您应该期望通过 SSO。
默认应该是 SSO - 因此我在 Program.cs
builder.Services
.AddAuthentication(
options =>
{
// If an authentication cookie is present, use it to get authentication information
options.DefaultAuthenticateScheme =
CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
// If authentication is required, and no cookie is present,
// use OAuth to sign in
options.DefaultChallengeScheme = "OAuth";
}
)
.AddCookie(
options =>
{
options.AccessDeniedPath = "/accessdenied";
}
)
.AddOAuth(
"OAuth",
(OAuthOptions options) =>
{
// abstracted out but takes care of claims, etc...
WebApp.Utils.OAuthHelper.Process(options, OAuthConfig);
}
);
但我的问题是 - 我该如何配置它来说明 - 如果 API 密钥 Header 存在,请不要理会 OAuth。
AuthenticationSchemeOptions
class has ForwardDefaultSelector
that allows any AuthenticationHandler
将身份验证事件转发给另一个处理程序。
因此,如果 API 密钥 header 不在 HTTP [=31] 中,那么您可以将 ApiKeyAuthenticationHandler
设置为默认值并使其将身份验证事件转发给 OAuth 处理程序=]s.
例如:假设您实现 ApiKeyAuthenticationHandler 如下:
// API Key options
public class ApiKeyAuthenticationOptions : AuthenticationSchemeOptions
{
public string ApiKeyHeaderName { get; set; } = "X-MY-API-KEY";
// Add more options here if needed
}
// API Key Authentication handler
public class ApiKeyAuthenticationHandler : AuthenticationHandler<ApiKeyAuthenticationOptions>
{
// Inject any additional services needed by your key handler here
public ApiKeyAuthenticationHandler(IOptionsMonitor<ApiKeyAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) : base(options, logger, encoder, clock)
{
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
// Validation logic here
// Check if the header exists
if (!Context.Request.Headers.TryGetValue(Options.ApiKeyHeaderName, out var headerValues))
{
// Header is not present fail
return AuthenticateResult.Fail("Invalid API key.");
}
// Header is present validate user
var user = await GetApiKeyUserAsync(headerValues.First());
if (user == null)
{
return AuthenticateResult.Fail("Invalid API key.");
}
// API Key is valid, generate a ClaimIdentity and Principal for the authenticated user
var identity = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, user)
}, Scheme.Name);
var principal = new ClaimsPrincipal(identity);
return AuthenticateResult.Success(new AuthenticationTicket(principal, null, Scheme.Name));
}
// Key validation logic here and you can map an API key to a user
private async Task<string?> GetApiKeyUserAsync(string key)
{
// Add your implementation here
if (key == "Alice's Key")
{
return "Alice";
}
if (key == "Bob's Key")
{
return "Bob";
}
return null;
}
}
现在在启动 class 中调用 AddAuthentication
并将 "ApiKey"
设置为默认值,并添加一个选择器函数来检查 HTTP Headers 是否存在密钥,如果密钥存在,则 return null
并让 Api 密钥处理程序处理身份验证,否则转发到“OAuth”。
builder.Services
.AddAuthentication(
options =>
{
options.DefaultAuthenticateScheme =
"ApiKey";
}
)
.AddScheme<ApiKeyAuthenticationOptions, ApiKeyAuthenticationHandler>("ApiKey", apiKeyOptions =>
{
// This scheme will forward Authentication to OAUTH if API Key header is not present
apiKeyOptions.ForwardDefaultSelector = (context) =>
{
// Check the HTTP Request for the presence of Header
if (!context.Request.Headers.TryGetValue(apiKeyOptions.ApiKeyHeaderName, out var headerValues))
{
// Header is not present, forward to OAuth
return "OAuth"; // "OAuth" is the scheme name you specified when you called "AddOAuth()
}
// Do not forward the authentication
return null;
};
})
// Add other schemes here