You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

在ASP.NET Core 8 + NSwag/OpenAPI3中配置支持可选身份验证的Swagger端点

在ASP.NET Core 8 + NSwag/OpenAPI3中配置支持可选身份验证的Swagger端点

我完全理解你的痛点——既要保持单端点设计简化客户端代码,又要让Swagger支持"可选带token"的请求逻辑。之前你尝试的[AllowAnonymous][Authorize]都是非黑即白的配置,不符合"可选"的需求。下面是一套经过验证的解决方案,核心思路是让API层面允许匿名访问,同时手动修改OpenAPI文档标记该端点支持可选的OAuth2授权

步骤1:自定义标记属性

首先,我们需要一个自定义属性来标记哪些端点需要"可选授权",方便后续过滤器识别:

[AttributeUsage(AttributeTargets.Method)]
public class OptionalAuthorizeAttribute : Attribute
{
    // 空属性,仅用作标记
}

步骤2:实现NSwag操作处理器

NSwag默认会根据[AllowAnonymous]清空端点的安全要求,我们需要通过自定义IOperationProcessor来手动添加可选的安全规则(既允许使用OAuth2授权,也允许匿名访问):

using NSwag.Generation.Processors;
using NSwag.Generation.Processors.Contexts;
using System.Reflection;

public class OptionalAuthorizationProcessor : IOperationProcessor
{
    public bool Process(OperationProcessorContext context)
    {
        // 检查当前Action是否标记了我们的自定义属性
        var hasOptionalAuth = context.MethodInfo.GetCustomAttributes(true)
            .Any(attr => attr is OptionalAuthorizeAttribute);

        if (!hasOptionalAuth) return true; // 不是目标端点,跳过处理

        // 清空NSwag自动生成的安全要求(因为[AllowAnonymous]会清空,但这里确保彻底清除)
        context.Operation.Security.Clear();

        // 获取你在NSwag配置中定义的OAuth2安全方案(这里假设你的安全方案ID是"OAuth2")
        if (!context.Document.SecuritySchemes.TryGetValue("OAuth2", out var oauthScheme))
            return true;

        // 添加两种安全要求:
        // 1. 使用OAuth2授权(需要携带token)
        context.Operation.Security.Add(new NSwag.OpenApiSecurityRequirement
        {
            { oauthScheme, new List<string>() } // 这里的空列表表示不需要特定scope
        });

        // 2. 不需要任何授权(匿名访问)
        context.Operation.Security.Add(new NSwag.OpenApiSecurityRequirement());

        return true;
    }
}

步骤3:注册处理器到NSwag配置

Program.cs中,将自定义处理器添加到NSwag的文档生成配置里:

builder.Services.AddOpenApiDocument(settings =>
{
    // 你的基础NSwag配置(比如标题、版本等)
    settings.Title = "Your API Title";
    settings.Version = "v1";

    // 注册可选授权处理器
    settings.OperationProcessors.Add(new OptionalAuthorizationProcessor());

    // 别忘了配置你的OAuth2安全方案(这里是示例,根据你的实际认证服务调整)
    settings.AddSecurity("OAuth2", new NSwag.OpenApiSecurityScheme
    {
        Type = NSwag.OpenApiSecuritySchemeType.OAuth2,
        Flows = new NSwag.OpenApiOAuthFlows
        {
            AuthorizationCode = new NSwag.OpenApiOAuthFlow
            {
                AuthorizationUrl = new Uri("https://your-auth-server/connect/authorize"),
                TokenUrl = new Uri("https://your-auth-server/connect/token"),
                Scopes = new Dictionary<string, string>
                {
                    { "api.read", "Read access to API resources" }
                    // 其他需要的scope
                }
            }
        }
    });
});

步骤4:标记目标端点

在你的Action上同时添加[AllowAnonymous](让API允许匿名请求)和[OptionalAuthorize](告诉处理器要修改安全规则):

[AllowAnonymous]
[OptionalAuthorize]
[HttpGet]
public ActionResult<SomeDto> GetInfo(bool includePrivateInfo)
{
    if (includePrivateInfo)
    {
        // 内部权限检查:如果需要私有信息,必须登录
        _authorizationService.RequireLoggedIn();
    }

    var result = _dataService.GetInfo(includePrivateInfo);
    return result;
}

为什么这个方案能解决问题?

  • API层面:[AllowAnonymous]确保ASP.NET Core不会拒绝匿名请求,完全由你内部的includePrivateInfo逻辑控制权限。
  • Swagger层面:我们手动给OpenAPI文档添加了两种安全要求,Swagger UI会识别为"可选授权"——如果你已经在Swagger中完成了OAuth2授权(获取了token),调用该端点时会自动携带Authorization头;如果未授权,也能正常发起请求。
  • 客户端层面:保持了单端点设计,客户端可以根据用户登录状态决定是否携带token,完全符合你的"有token就发,没有就不发"的设计。

测试验证

  1. 在Swagger UI中,未点击"Authorize"按钮时:

    • 调用GetInfo(includePrivateInfo=false):正常返回数据,无Authorization头。
    • 调用GetInfo(includePrivateInfo=true):API返回403 Forbidden(符合内部权限逻辑)。
  2. 在Swagger UI中完成OAuth2授权后:

    • 调用GetInfo(includePrivateInfo=false):自动携带Authorization头,API正常返回数据。
    • 调用GetInfo(includePrivateInfo=true):携带Authorization头,API返回包含私有信息的数据(如果token有效)。

这样既满足了API的业务逻辑,又让Swagger客户端完美支持可选token的需求,同时保持了代码的简洁性。

火山引擎 最新活动