如何使用Swagger生成CORS选项

7

我们正在开展的项目中,我们正在自动生成Swagger文件。但是目前我们在CORS部分遇到了困难。

我们使用亚马逊API网关导入API功能。为了将其与Swagger和CORS结合使用,我们必须在源代码中创建一个额外的操作(operation),允许每个API方法(operation)进行CORS(options)!例如:

    [HttpOptions]
    [Route("{id}")]
    [ProducesResponseType((int)HttpStatusCode.OK)]
    public IActionResult UserOptions()
    {
        return new OkResult();
    }

如您所见,这使得代码变得非常混乱。虽然这只是一个临时解决方案,但我们找不到其他更好的办法。有没有办法在Swagger定义文件中自动生成它?或者我们应该怎么做,亚马逊API网关要求这样做(文档链接:http://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html)。


你正在使用哪个版本的Swashbuckle? - Helder Sepulveda
@HelderSepu:我们正在使用版本1.0.0 => "Swashbuckle.AspNetCore" Version="1.0.0" - Rob Van Pamel
4个回答

4
你可以通过 x-amazon-apigateway-integration swagger 扩展来驱动 API 网关。
使用 Swashbuckle 文档过滤器,你可以在所有路径上生成一个选项操作,而无需在控制器中对应某个操作。
下面是一个示例代码,它将为 Swagger 中的所有路径生成一个选项操作,并使用 Swagger 扩展在这些 OPTION 方法上生成一个模拟的 API 网关。
    public class AddCorsApiGatewayDocumentFilter : IDocumentFilter
    {
        private Operation BuildCorsOptionOperation()
        {
            var response = new Response
            {
                Description = "Successful operation",
                Headers = new Dictionary<string, Header>
                {
                    { "Access-Control-Allow-Origin", new Header(){Type="string",Description="URI that may access the resource" } },
                    { "Access-Control-Allow-Methods", new Header(){Type="string",Description="Method or methods allowed when accessing the resource" } },
                    { "Access-Control-Allow-Headers", new Header(){Type="string",Description="Used in response to a preflight request to indicate which HTTP headers can be used when making the request." } },
                }
            };
            return new Operation
            {
                Consumes = new List<string> { "application/json" },
                Produces = new List<string> { "application/json" },
                Responses = new Dictionary<string, Response>{{"200",response}}
            };
        }

        private object BuildApiGatewayIntegrationExtension()
        {
            return new
            {
                responses = new
                {
                    @default = new
                    {
                        statusCode = "200",
                        responseParameters = new Dictionary<string, string>
                            {
                                { "method.response.header.Access-Control-Allow-Methods", "'POST,GET,OPTIONS'" },
                                { "method.response.header.Access-Control-Allow-Headers", "'Content-Type,X-Amz-Date,Authorization,X-Api-Key'"},
                                { "method.response.header.Access-Control-Allow-Origin", "'*'"}
                            }
                    },
                },
                passthroughBehavior = "when_no_match",
                requestTemplates = new Dictionary<string, string> { { "application/json", "{\"statusCode\": 200}" } },
                type = "mock"
            };
        }

        public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
        {
            foreach (var path in swaggerDoc.Paths)
            {
                var corsOptionOperation = BuildCorsOptionOperation();
                var awsApiGatewayExtension = BuildApiGatewayIntegrationExtension();
                corsOptionOperation.Extensions.Add("x-amazon-apigateway-integration", awsApiGatewayExtension);
                path.Value.Options = corsOptionOperation;
            }
        }
    }

不要忘记在 swashbuckle 中注册该过滤器:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });
            c.DocumentFilter<AddCorsApiGatewayDocumentFilter>();
        });
    }

2

我曾经遇到过完全相同的问题,不过是和Azure API管理结合使用时出现的。我使用了asidis的代码,并对其进行了修改以适应我的需求。

显然,我删除了AWS扩展部分,并使用了更新版本的Swashbuckle.AspNetCore包(5.5.1)。

public class CorsDocumentFilter : IDocumentFilter
{
    private const string AcaOrigin = "Access-Control-Allow-Origin";
    private const string AcaMethods = "Access-Control-Allow-Methods";
    private const string AcaHeaders = "Access-Control-Allow-Headers";

    private static OpenApiOperation BuildCorsOptionOperation(OpenApiOperation operation)
    {
        var response = new OpenApiResponse
        {
            Description = "Successful operation",
            Headers = new Dictionary<string, OpenApiHeader>
            {
                { AcaOrigin, new OpenApiHeader {Description = "URI that may access the resource" } },
                { AcaMethods, new OpenApiHeader {Description = "Method or methods allowed when accessing the resource" } },
                { AcaHeaders, new OpenApiHeader {Description = "Used in response to a preflight request to indicate which HTTP headers can be used when making the request." } },
            }
        };

        return new OpenApiOperation
        {
            Summary = "CORS Preflight request",

            // Path parameters are required for Azure APIM
            Parameters = operation.Parameters.Where(x => x.In == ParameterLocation.Path).ToList(),
            Tags = new List<OpenApiTag> { new OpenApiTag { Name = "CORS" } },
            Responses = new OpenApiResponses
            {
                { "200", response }
            },
        };
    }
    
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        foreach (var path in swaggerDoc.Paths)
        {
            var operation = path.Value.Operations.Values.First();
            var corsOptionOperation = BuildCorsOptionOperation(operation);
            path.Value.Operations.Add(OperationType.Options, corsOptionOperation);
        }
    }
}

2
我曾经遇到过同样的问题,最终我用 Java 创建了一个实用程序,自动将这些头部添加到 Swagger JSON 中。在导入到 API Gateway 之前,您可以运行它,并导入启用了 CORS 的所有方法的输出 JSON。在 Swagger JSON 中为所有方法添加这些头部是一项繁琐的任务。 https://github.com/anandlalvb/SwaggerToAPIGateway
            "headers": {
            "Access-Control-Allow-Origin": {
                "type": "string"
            },
            "Access-Control-Allow-Methods": {
                "type": "string"
            },
            "Access-Control-Allow-Headers": {
                "type": "string"
            }
        }

我希望这个工具可以帮助您轻松地完成这个任务。

0

按照控制台中的一键式功能,执行“启用CORS”的步骤,然后部署API,最后进入阶段并将API导出回Swagger。

现在,您可以检查Swagger以了解如何在自己的Swagger中配置CORS。


谢谢您的回复,但是我想以自动化的方式创建这些选项。在我们的项目中,我们只需将Swagger文件交付给AWS合作伙伴,然后他们将其导入API网关。 - Rob Van Pamel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接