You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core 6 Minimal API能否自定义授权特性适配认证中间件?

实现ASP.NET Core 6 Minimal API自定义授权扩展方法

1. 定义自定义授权元数据类

先创建两个元数据类,用来存储路由的授权配置信息:

// 标记需要特定角色授权的元数据
public class CustomAuthorizationMetadata
{
    public string[] RequiredRoles { get; }

    public CustomAuthorizationMetadata(params string[] requiredRoles)
    {
        RequiredRoles = requiredRoles;
    }
}

// 标记允许匿名访问的元数据
public class AllowAnonymousMetadata
{
}

2. 编写路由扩展方法

给RouteHandlerBuilder(Minimal API路由的返回类型)实现扩展方法,通过WithMetadata给路由添加自定义元数据:

public static class RouteAuthorizationExtensions
{
    // 模拟原生RequiresAuthorization,支持传入角色列表
    public static RouteHandlerBuilder RequiresCustomAuthorization(this RouteHandlerBuilder builder, params string[] roles)
    {
        return builder.WithMetadata(new CustomAuthorizationMetadata(roles));
    }

    // 模拟原生AllowAnonymous
    public static RouteHandlerBuilder AllowCustomAnonymous(this RouteHandlerBuilder builder)
    {
        return builder.WithMetadata(new AllowAnonymousMetadata());
    }
}

3. 实现自定义授权中间件

中间件从当前请求的Endpoint中提取元数据,据此执行授权判断:

public class CustomAuthorizationMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task InvokeAsync(HttpContext context)
    {
        var endpoint = context.GetEndpoint();
        if (endpoint == null)
        {
            await _next(context);
            return;
        }

        // 优先判断是否允许匿名:存在AllowAnonymousMetadata则跳过授权
        var allowAnonymous = endpoint.Metadata.GetMetadata<AllowAnonymousMetadata>();
        if (allowAnonymous != null)
        {
            await _next(context);
            return;
        }

        // 判断是否需要角色授权:读取CustomAuthorizationMetadata
        var authMetadata = endpoint.Metadata.GetMetadata<CustomAuthorizationMetadata>();
        if (authMetadata != null)
        {
            var user = context.User;
            // 未认证直接返回401
            if (!user.Identity.IsAuthenticated)
            {
                context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                return;
            }

            // 检查用户是否拥有所需角色
            var hasRequiredRole = authMetadata.RequiredRoles.Any(role => user.IsInRole(role));
            if (!hasRequiredRole)
            {
                context.Response.StatusCode = StatusCodes.Status403Forbidden;
                return;
            }
        }

        // 授权通过,继续执行后续逻辑
        await _next(context);
    }
}

4. 注册中间件并使用扩展方法

在Program.cs中按顺序注册中间件(需放在认证中间件之后、路由之前),然后在路由定义中直接调用扩展方法:

var builder = WebApplication.CreateBuilder(args);

// 注册你的认证服务(如JWT、Cookie等,根据实际场景配置)
builder.Services.AddAuthentication(...);

var app = builder.Build();

// 先启用认证,再启用自定义授权中间件
app.UseAuthentication();
app.UseMiddleware<CustomAuthorizationMiddleware>();

app.UseEndpoints(x =>
{
    // 要求Admins角色才能访问
    x.MapGet("/api/something", () => Results.Ok("Admin-only content"))
      .RequiresCustomAuthorization("Admins");

    // 允许匿名访问
    x.MapGet("/api/public", () => Results.Ok("Public content"))
      .AllowCustomAnonymous();

    // 未配置授权规则的路由:默认不做授权检查(可根据需求调整中间件逻辑)
    x.MapGet("/api/default", () => Results.Ok("Default content"));
});

app.Run();

核心逻辑说明

  • ASP.NET Core路由的Metadata是存储路由附加信息的容器,通过WithMetadata可以给路由绑定任意自定义元数据。
  • 中间件通过context.GetEndpoint()获取当前匹配的路由端点,再用Metadata.GetMetadata<T>()提取自定义元数据,以此判断路由的授权规则。
  • 可根据业务需求扩展元数据类,比如添加权限策略、自定义规则等,让授权逻辑更灵活。

内容的提问来源于stack exchange,提问作者enriquein

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 03:25:49