首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >不使用Swashbuckle和ASPNetZero / ABP的无记名令牌

不使用Swashbuckle和ASPNetZero / ABP的无记名令牌
EN

Stack Overflow用户
提问于 2021-05-11 15:34:30
回答 1查看 1.3K关注 0票数 1

我试图在Swagger规范和SwaggerUI中包含安全头信息,因为我希望第三方系统能够轻松地使用我的API,并能够使用Swagger CodeGen和NSwag等CodeGen工具来生成客户端库。

我使用Swashbuckle / SwaggerGen在运行时自动生成文档。我的API使用了承载令牌身份验证,我希望我的SwaggerDocs反映我的身份验证方案。我还可以在我的SwaggerDocs中看到所需的安全头信息,并且能够让客户端在尝试API调用时通过SwaggerUI测试身份验证。

但是,我无法成功地将我的安全头信息显示在我自己的解决方案上。

这就是我在调试期间通过本地SwaggerDocs查看SwaggerUI时所看到的:

请注意,生成的OAS3标记在通过https://editor.swagger.io/运行时正确呈现。

下面是由Swashbuckle /SwaggerGen生成的实际标记:

代码语言:javascript
复制
{
    "openapi": "3.0.1",
    "info": {
        "title": "MyDemo Host API v1",
        "version": "v1"
    },
    "paths": {
        "/api/services/app/Tenant/CreateTenant": {
            "post": {
                "tags": [
                    "Tenant"
                ],
                "operationId": "ApiServicesAppTenantCreatetenantPost",
                "requestBody": {
                    "content": {
                        "application/json-patch+json": {
                            "schema": {
                                "allOf": [
                                    {
                                        "$ref": "#/components/schemas/CreateTenantInput"
                                    }
                                ]
                            }
                        },
                        "application/json": {
                            "schema": {
                                "allOf": [
                                    {
                                        "$ref": "#/components/schemas/CreateTenantInput"
                                    }
                                ]
                            }
                        },
                        "text/json": {
                            "schema": {
                                "allOf": [
                                    {
                                        "$ref": "#/components/schemas/CreateTenantInput"
                                    }
                                ]
                            }
                        },
                        "application/*+json": {
                            "schema": {
                                "allOf": [
                                    {
                                        "$ref": "#/components/schemas/CreateTenantInput"
                                    }
                                ]
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Success",
                        "content": {
                            "text/plain": {
                                "schema": {
                                    "$ref": "#/components/schemas/SwaggerDocResponseWrapper"
                                }
                            },
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/SwaggerDocResponseWrapper"
                                }
                            },
                            "text/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/SwaggerDocResponseWrapper"
                                }
                            }
                        }
                    }
                },
                "security": [
                    {
                        "bearer": []
                    }
                ]
            }
        }
    },
    "components": {
        "schemas": {
            "CreateTenantInput": {
                "required": [
                    "adminEmailAddress",
                    "name",
                    "tenancyName"
                ],
                "type": "object",
                "properties": {
                    "tenancyName": {
                        "maxLength": 64,
                        "minLength": 0,
                        "pattern": "^[a-zA-Z][a-zA-Z0-9_-]{1,}$",
                        "type": "string"
                    },
                    "name": {
                        "maxLength": 128,
                        "minLength": 0,
                        "type": "string"
                    },
                    "adminEmailAddress": {
                        "maxLength": 256,
                        "minLength": 0,
                        "type": "string",
                        "format": "email"
                    },
                    "adminPassword": {
                        "maxLength": 128,
                        "minLength": 0,
                        "type": "string",
                        "nullable": true
                    },
                    "connectionString": {
                        "maxLength": 1024,
                        "type": "string",
                        "nullable": true
                    },
                    "shouldChangePasswordOnNextLogin": {
                        "type": "boolean"
                    },
                    "sendActivationEmail": {
                        "type": "boolean"
                    },
                    "editionId": {
                        "type": "integer",
                        "format": "int32",
                        "nullable": true
                    },
                    "isActive": {
                        "type": "boolean"
                    },
                    "subscriptionEndDateUtc": {
                        "type": "string",
                        "format": "date-time",
                        "nullable": true
                    },
                    "isInTrialPeriod": {
                        "type": "boolean"
                    },
                    "onSellingPartnerId": {
                        "type": "integer",
                        "format": "int32",
                        "nullable": true
                    },
                    "onSellingPartner": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/OnSellingPartnerDto"
                            }
                        ],
                        "nullable": true
                    },
                    "contactPersonFirstName": {
                        "maxLength": 32,
                        "type": "string",
                        "nullable": true
                    },
                    "contactPersonLastName": {
                        "maxLength": 32,
                        "type": "string",
                        "nullable": true
                    },
                    "contactNumber": {
                        "maxLength": 24,
                        "type": "string",
                        "nullable": true
                    },
                    "contactEmail": {
                        "maxLength": 256,
                        "type": "string",
                        "nullable": true
                    },
                    "taxNumber": {
                        "maxLength": 24,
                        "type": "string",
                        "nullable": true
                    },
                    "registeredName": {
                        "maxLength": 256,
                        "type": "string",
                        "nullable": true
                    },
                    "tenantBillingAddress": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/TenantBillingAddressInput"
                            }
                        ],
                        "nullable": true
                    }
                },
                "additionalProperties": false
            },
            "ValidationError": {
                "type": "object",
                "properties": {
                    "message": {
                        "type": "string",
                        "nullable": true
                    },
                    "members": {
                        "type": "array",
                        "items": {
                            "type": "string"
                        },
                        "nullable": true
                    }
                },
                "additionalProperties": false
            },
            "SwaggerDocResponseWrapper": {
                "type": "object",
                "properties": {
                    "result": {
                        "type": "string",
                        "nullable": true
                    },
                    "targetUrl": {
                        "type": "string",
                        "nullable": true
                    },
                    "success": {
                        "type": "boolean"
                    },
                    "error": {
                        "allOf": [
                            {
                                "$ref": "#/components/schemas/ResponseError"
                            }
                        ],
                        "nullable": true
                    },
                    "unauthorizedRequest": {
                        "type": "boolean"
                    },
                    "__Abp": {
                        "type": "boolean"
                    }
                },
                "additionalProperties": false
            },
            "OnSellingPartnerDto": {
                "type": "object",
                "properties": {
                    "name": {
                        "type": "string",
                        "nullable": true
                    },
                    "isActive": {
                        "type": "boolean"
                    },
                    "registeredName": {
                        "type": "string",
                        "nullable": true
                    },
                    "taxNumber": {
                        "type": "string",
                        "nullable": true
                    },
                    "contactNumber": {
                        "type": "string",
                        "nullable": true
                    },
                    "contactPersonFirstName": {
                        "type": "string",
                        "nullable": true
                    },
                    "contactPersonLastName": {
                        "type": "string",
                        "nullable": true
                    },
                    "contactEmail": {
                        "type": "string",
                        "nullable": true
                    },
                    "id": {
                        "type": "integer",
                        "format": "int32"
                    }
                },
                "additionalProperties": false
            },
            "TenantBillingAddressInput": {
                "type": "object",
                "properties": {
                    "streetAddress": {
                        "maxLength": 256,
                        "minLength": 0,
                        "type": "string",
                        "nullable": true
                    },
                    "region": {
                        "maxLength": 64,
                        "minLength": 0,
                        "type": "string",
                        "nullable": true
                    },
                    "city": {
                        "maxLength": 64,
                        "minLength": 0,
                        "type": "string",
                        "nullable": true
                    },
                    "countryId": {
                        "type": "integer",
                        "format": "int32",
                        "nullable": true
                    },
                    "regionCode": {
                        "maxLength": 6,
                        "minLength": 0,
                        "type": "string",
                        "nullable": true
                    }
                },
                "additionalProperties": false
            },
            "ResponseError": {
                "type": "object",
                "properties": {
                    "code": {
                        "type": "integer",
                        "format": "int32"
                    },
                    "message": {
                        "type": "string",
                        "nullable": true
                    },
                    "details": {
                        "type": "string",
                        "nullable": true
                    },
                    "validationErrors": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/ValidationError"
                        },
                        "nullable": true
                    }
                },
                "additionalProperties": false
            }
        },
        "securitySchemes": {
            "bearer": {
                "type": "http",
                "description": "Specify the authorization token.",
                "scheme": "bearer",
                "bearerFormat": "JWT"
            }
        }
    },
    "security": [
        {}
    ]
}

环境:

  • AspNetZero Core & JQuery v10.3.0 (.Net 5)
  • Abp

(5.6.3)和Swashbuckle.AspNetCore.NewtonSoft (6.1.4)

下面的代码是从ConfiguredServices方法在Startup.cs中调用的

代码语言:javascript
复制
        public override void InstallServices(IHostEnvironment hostEnvironment, IServiceCollection services, IConfiguration configuration)
        {
            if (WebConsts.SwaggerUiEnabled)
            {
                //Swagger - Enable this line and the related lines in Configure method to enable swagger UI
                services.AddSwaggerGen(options =>
                {
                    options.SwaggerDoc(ApiNames.HostApiv1, new OpenApiInfo { Title = ApiTitles.HostApiv1, Version = "v1" });
                    options.SwaggerDoc(ApiNames.PartnerApiv1, new OpenApiInfo { Title = ApiTitles.PartnerApiv1, Version = "v1" });
                    options.SwaggerDoc(ApiNames.TenantApiv1, new OpenApiInfo { Title = ApiTitles.TenantApiv1, Version = "v1" });

                    OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme()
                    {
                        Name = "Bearer",
                        BearerFormat = "JWT",
                        Scheme = "bearer",
                        Description = "Specify the authorization token.",
                        In = ParameterLocation.Header,
                        Type = SecuritySchemeType.Http,
                    };

                    OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement()
                    {
                        {securityDefinition, new string[] { }},
                    };

                    options.AddSecurityDefinition("bearer", securityDefinition);
                    // Make sure swagger UI requires a Bearer token to be specified
                    options.AddSecurityRequirement(securityRequirements);

                    options.DocInclusionPredicate((docName, apiDesc) =>
                    {
                        if (!apiDesc.ActionDescriptor.IsControllerAction())
                        {
                            return false;
                        }

                        apiDesc.TryGetMethodInfo(out MethodInfo methodInfo);

                        var actionDocs = methodInfo.GetCustomAttributes<SwaggerDocAttribute>()
                            .SelectMany(a => a.IncludeInDocuments);

                        var controllerDocs = methodInfo.DeclaringType.GetCustomAttributes<SwaggerDocAttribute>()
                            .SelectMany(a => a.IncludeInDocuments);

                        switch (docName)
                        {
                            case ApiNames.HostApiv1:
                                return apiDesc.GroupName == null ||
                                       actionDocs.Contains(ApiNames.HostApiv1) ||
                                       controllerDocs.Contains(ApiNames.HostApiv1);
                            case ApiNames.PartnerApiv1:
                                return apiDesc.GroupName == null ||
                                       actionDocs.Contains(ApiNames.PartnerApiv1) ||
                                       controllerDocs.Contains(ApiNames.PartnerApiv1);
                            case ApiNames.TenantApiv1:
                                return apiDesc.GroupName == null ||
                                       actionDocs.Contains(ApiNames.TenantApiv1) ||
                                       controllerDocs.Contains(ApiNames.TenantApiv1);
                            default:
                                return true;
                        }
                    });

                    options.IgnoreObsoleteActions();
                    options.IgnoreObsoleteProperties();
                    options.OrderActionsBy((apiDesc) => $"{apiDesc.RelativePath}");
                    options.ParameterFilter<SwaggerEnumParameterFilter>();
                    options.SchemaFilter<SwaggerEnumSchemaFilter>();
                    options.OperationFilter<SwaggerOperationIdFilter>();
                    options.OperationFilter<SwaggerOperationFilter>();
                    options.CustomDefaultSchemaIdSelector();
                    options.UseAllOfToExtendReferenceSchemas();


                    var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
                    var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
                    options.IncludeXmlComments(xmlPath);

                }).AddSwaggerGenNewtonsoftSupport();
            }
        }

更多背景信息:我正在为API的不同类型的使用者(内部/主机应用程序;合作伙伴应用程序;普通租户/客户端应用程序)将我的API文档生成单独的SwaggerDocs。TI用SwaggerDocsAttribute装饰我的SwaggerDocsAttribute(在运行时被ABP/AspNetZero动态地用作类似REST的服务),它用来描述一个或多个Swagger文档应该将它包含在文档中的内容。

代码语言:javascript
复制
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
    public class SwaggerDocAttribute: Attribute
    {
        public SwaggerDocAttribute(params string[] includeInDocuments)
        {
            IncludeInDocuments = includeInDocuments;
        }

        public string[] IncludeInDocuments { get; }
    }

示例用法:

代码语言:javascript
复制
    [SwaggerDoc(ApiNames.HostApiv1, ApiNames.PartnerApiv1, ApiNames.TenantApiv1)]
    public class SystemStatusAppService: MyDemoAppServiceBase, ISystemStatusAppService
    {
        [ProducesResponseType(200, Type = typeof(SwaggerDocResponseWrapper))]
        public async Task Ping()
        {
            //Do nothing - will return status code 200
        }

        [AbpAuthorize()]
        [ProducesResponseType(200, Type = typeof(SwaggerDocResponseWrapper))]
        public async Task PingWithAuth()
        {
            //Do nothing - will return status code 200
        }
    }
EN

回答 1

Stack Overflow用户

发布于 2021-05-12 10:10:56

您可能需要在需求中添加对定义的引用。

代码语言:javascript
复制
OpenApiSecurityScheme securityDefinition = new OpenApiSecurityScheme()
{
    BearerFormat = "JWT",
    Scheme = "bearer",
    Description = "Specify the authorization token.",
    Type = SecuritySchemeType.Http,
};

options.AddSecurityDefinition("Bearer", securityDefinition);

OpenApiSecurityRequirement securityRequirements = new OpenApiSecurityRequirement
{
    {
        new OpenApiSecurityScheme
        {
            Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
        },
        new string[] {}
    }
};

options.AddSecurityRequirement(securityRequirements);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67489946

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档