使用需要会话 api 密钥的 .NET Minimal API 创建 API

Ton*_*Nam 5 c# asp.net-web-api

该视频非常精彩,展示了如何使用 .net 6 创建最小 API:

https://www.youtube.com/watch?v=eRJFNGisJEo

令人惊奇的是它如何使用依赖注入来获取端点内所需的大部分内容。例如,如果我需要自定义标头的值,我会这样:

app.MapGet("/get-custom-header", ([FromHeader(Name = "User-Agent")] string data) =>
{
    return $"User again is: {data}";
});
Run Code Online (Sandbox Code Playgroud)

我可以有另一个端点,我可以在其中访问整个 httpContext,如下所示:

app.MapGet("/foo", (Microsoft.AspNetCore.Http.HttpContext c) =>
{
    var path = c.Request.Path;
    return path;
});
Run Code Online (Sandbox Code Playgroud)

我什至可以使用以下代码注册我自己的类:builder.Services.AddTransient<TheClassIWantToRegister>()

app.MapGet("...如果我注册我的自定义类,我将能够在每次需要时在端点 ( )上创建该类的实例


无论如何回到问题。当用户登录时,我向他发送以下内容:

{
  "ApiKey": "1234",
  "ExpirationDate": blabla bla
  .....
}
Run Code Online (Sandbox Code Playgroud)

用户必须发送1234令牌才能使用 API。我怎样才能避免重复我的代码,如下所示:

app.MapGet("/getCustomers", ([FromHeader(Name = "API-KEY")] string apiToken) =>
{
    // validate apiToken agains DB
    if(validationPasses)
       return Database.Customers.ToList();
    else
       // return unauthorized
});
Run Code Online (Sandbox Code Playgroud)

我尝试创建一个自定义类RequiresApiTokenKey并将该类注册为,builder.Services.AddTransient<RequiresApiTokenKey>()以便我的 API 知道如何在需要时创建该类的实例,但例如如何访问该类中的当前 http 上下文?如何避免必须重复检查标头 API-KEY 标头在每个需要它的方法中是否有效?

Smi*_*art 11

根据我的评论进行了测试。

这将在每个请求上调用中间件中的 Invoke 方法,您可以在此处进行检查。

可能更好的方法是使用AuthenticationHandler. 使用此功能意味着您可以归因于各个端点来完成 API 密钥检查,而不是所有传入请求

但是,我认为这仍然有用,中间件可以用于您想要对每个请求执行的任何操作

使用中间件

程序.cs:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

//our custom middleware extension to call UseMiddleware
app.UseAPIKeyCheckMiddleware();

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.MapGet("/", () => "Hello World!");

app.Run();
Run Code Online (Sandbox Code Playgroud)

APIKeyCheckMiddleware.cs

using Microsoft.Extensions.Primitives;

internal class APIKeyCheckMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task InvokeAsync(HttpContext httpContext)
    {
        
        //we could inject here our database context to do checks against the db
        if (httpContext.Request.Headers.TryGetValue("API-KEY", out StringValues value))
        {
            //do the checks on key
            var apikey = value;
        }
        else
        {
            //return 403
            httpContext.Response.StatusCode = 403;
        }
        
        await _next(httpContext);
    }
}

// Extension method used to add the middleware to the HTTP request pipeline.
public static class APIKeyCheckMiddlewareExtensions
{
    public static IApplicationBuilder UseAPIKeyCheckMiddleware(this IApplicationBuilder builder)
    {
        
        return builder.UseMiddleware<APIKeyCheckMiddleware>();
    }
}
Run Code Online (Sandbox Code Playgroud)