【问题标题】:ASP.NET core - simple API key authenticationASP.NET 核心 - 简单的 API 密钥身份验证
【发布时间】:2022-01-13 13:20:51
【问题描述】:

我正在尝试为控制器中的某些 API 构建一个超级简单的 API 密钥身份验证。为此,我在ConfigureServices()

            services.AddAuthorization(options =>
            {
                options.AddPolicy(Auth.Constants.WebmasterPolicyName, policy =>
                    policy.RequireAssertion(context =>
                    {
                        if (context.Resource is HttpContext httpContext)
                        {
                            if (httpContext.Request.Headers.TryGetValue("X-API-KEY", out var header))
                            {
                                var val = header.FirstOrDefault()?.ToLower();
                                if (val == "my-super-secret-key")
                                {
                                    return Task.FromResult(true);
                                }
                            }
                        }
                        return Task.FromResult(false);
                    }));
            });

我已经用这个装饰了一个 API:

[HttpDelete("{itemId:guid}")]
[Authorize(Policy = Auth.Constants.WebmasterPolicyName)]
public async Task<ActionResult> DeleteCatalogItemAsync(Guid itemId)

当我在请求中设置正确的 API 密钥时,这非常有效。

问题是负例:当密钥丢失或错误时,我会得到 500 错误:

System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).
   at Microsoft.AspNetCore.Authentication.AuthenticationService.ChallengeAsync(HttpContext context, String scheme, AuthenticationProperties properties)
   at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at AlwaysOn.CatalogService.Startup.<>c__DisplayClass5_0.<<Configure>b__3>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)

但我不确定如何处理该消息。我只是希望它向客户端返回 401 响应。

【问题讨论】:

  • configure()中app.UseAuthentication()和app.UseAuthorization()的顺序是什么?我怀疑通过您明确授权,它不会调用身份验证处理程序,但如果身份验证失败,它会调用未设置为处理任何方案的身份验证处理程序。这是一个非常混乱的领域!
  • 错误可能是由操作系统而不是您的应用程序返回的。如果它是由您的应用返回的,请参见以下内容:docs.microsoft.com/en-us/aspnet/core/web-api/…
  • @LukeBriner 现在我里面没有AddAuthentication() - 因为我不知道该放什么?!
  • 我们有这个: services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddScheme("Basic", null) .AddScheme("Bearer", null) .AddScheme ("Psk", null);
  • API 密钥认证不应该以这种方式实现。请查看this blog 帖子寻求帮助。

标签: c# asp.net-core .net-6.0


【解决方案1】:

我们可以创建一个自定义的ApiKeyMiddleware 来实现simple API key authentication

这有点类似于我们在自定义属性中所做的,但您会注意到这里的主要区别是我们不能直接设置上下文的响应对象,而是必须分别分配状态码和消息。

示例代码:

using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Threading.Tasks;

namespace SecuringWebApiUsingApiKey.Middleware
{
public class ApiKeyMiddleware
{
    private readonly RequestDelegate _next;
    private const string APIKEYNAME = "ApiKey";
    public ApiKeyMiddleware(RequestDelegate next)
    {
        _next = next;
    }
    public async Task InvokeAsync(HttpContext context)
    {
        if (!context.Request.Headers.TryGetValue(APIKEYNAME, out var extractedApiKey))
        {
            context.Response.StatusCode = 401;
            await context.Response.WriteAsync("Api Key was not provided. (Using ApiKeyMiddleware) ");
            return;
        }

        var appSettings = context.RequestServices.GetRequiredService<IConfiguration>();

        var apiKey = appSettings.GetValue<string>(APIKEYNAME);

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

        await _next(context);
    }
}
}

更多详情,我们可以参考这篇博客。

Secure ASP.NET Core Web API using API Key Authentication

【讨论】:

    猜你喜欢
    • 2017-05-23
    • 1970-01-01
    • 1970-01-01
    • 2021-06-11
    • 2017-01-04
    • 2017-05-13
    • 2019-08-05
    • 2021-06-26
    • 1970-01-01
    相关资源
    最近更新 更多