From 15ea07aad1dd7ac9338dead1096e8021892d98c0 Mon Sep 17 00:00:00 2001 From: kesonan Date: Sun, 27 Apr 2025 23:43:37 +0800 Subject: [PATCH] goctl: support custom swagger authentication (#4811) --- tools/goctl/api/swagger/const.go | 4 ---- tools/goctl/api/swagger/example/example.api | 6 +++++ .../goctl/api/swagger/example/example_cn.api | 6 ++++- tools/goctl/api/swagger/path.go | 6 ++--- tools/goctl/api/swagger/swagger.go | 24 ++++++++++--------- 5 files changed, 27 insertions(+), 19 deletions(-) diff --git a/tools/goctl/api/swagger/const.go b/tools/goctl/api/swagger/const.go index bee71ef89..1f2d94c7c 100644 --- a/tools/goctl/api/swagger/const.go +++ b/tools/goctl/api/swagger/const.go @@ -29,8 +29,4 @@ const ( schemeHttps = "https" defaultHost = "127.0.0.1" defaultBasePath = "/" - - swaggerSecurityDefinitionBearerAuth = "BearerAuth" - swaggerSecurityDefinitionName = "Authorization" - swaggerSecurityDefinitionIn = "header" ) diff --git a/tools/goctl/api/swagger/example/example.api b/tools/goctl/api/swagger/example/example.api index 40ab765a9..383155677 100644 --- a/tools/goctl/api/swagger/example/example.api +++ b/tools/goctl/api/swagger/example/example.api @@ -17,6 +17,10 @@ info ( basePath: "/v1" // basePath corresponding to Swagger,default value is `/` wrapCodeMsg: "true" // to wrap in the universal code-msg structure, like {"code":0,"msg":"OK","data":$data} bizCodeEnumDescription: "1001-User not login
1002-User permission denied" // enums of business error codes, in JSON format, with the key being the business error code and the value being the description of that error code. This only takes effect when wrapCodeMsg is set to true. + // securityDefinitionsFromJson is a custom authentication configuration, and the JSON content will be directly inserted into the securityDefinitions of Swagger. + // Format reference: https://swagger.io/specification/v2/#security-definitions-object + // You can declare authType in the @server of the API to specify the authentication type used for its routes. + securityDefinitionsFromJson: `{"apiKey":{"description":"apiKey type description","type":"apiKey","name":"x-api-key","in":"header"}}` ) type ( @@ -42,6 +46,8 @@ type ( @server ( tags: "query" // tags corresponding to Swagger summary: "query API set" // summary corresponding to Swagger + prefix: v1 + authType: apiKey // Specifies the authentication type used for this route, which is the name defined in securityDefinitionsFromJson. ) service Swagger { @doc ( diff --git a/tools/goctl/api/swagger/example/example_cn.api b/tools/goctl/api/swagger/example/example_cn.api index 509cf1ddb..48b2156aa 100644 --- a/tools/goctl/api/swagger/example/example_cn.api +++ b/tools/goctl/api/swagger/example/example_cn.api @@ -17,6 +17,10 @@ info ( basePath: "/v1" // 对应 swagger 的 basePath,不填默认为 / wrapCodeMsg: "true" // 是否用 code-msg 通用响应体,如果开启,则以格式 {"code":0,"msg":"OK","data":$data} 包括响应体 bizCodeEnumDescription: "1001-未登录
1002-无权限操作" // 业务错误码枚举描述,json 格式,key 为业务错误码,value 为该错误码的描述,仅当 wrapCodeMsg 为 true 时生效 + // securityDefinitionsFromJson 为自定义鉴权配置,json 内容将直接放入 swagger 的 securityDefinitions 中, + // 格式参考 https://swagger.io/specification/v2/#security-definitions-object + // 在 api 的 @server 中可声明 authType 来指定其路由使用的鉴权类型 + securityDefinitionsFromJson: `{"apiKey":{"description":"apiKey 类型鉴权自定义","type":"apiKey","name":"x-api-key","in":"header"}}` ) type ( @@ -43,7 +47,7 @@ type ( tags: "query 演示" // 对应 swagger 的 tags,可以对 swagger 中的 api 进行分组 summary: "query 类型接口集合" // 对应 swagger 的 summary prefix: v1 - jwt: Auth + authType: apiKey // 指定该路由使用的鉴权类型,值为 securityDefinitionsFromJson 中定义的名称 ) service Swagger { @doc ( diff --git a/tools/goctl/api/swagger/path.go b/tools/goctl/api/swagger/path.go index 04d4a8d2c..9c55c7265 100644 --- a/tools/goctl/api/swagger/path.go +++ b/tools/goctl/api/swagger/path.go @@ -61,12 +61,12 @@ func mergePathItem(old, new spec.PathItem) spec.PathItem { } func spec2Path(info apiSpec.Info, group apiSpec.Group, route apiSpec.Route) spec.PathItem { - needJwt := hasKey(group.Annotation.Properties, "jwt") + authType := getStringFromKVOrDefault(group.Annotation.Properties, "authType", "") var security []map[string][]string - if needJwt { + if len(authType) > 0 { security = []map[string][]string{ { - swaggerSecurityDefinitionBearerAuth: []string{}, + authType: []string{}, }, } } diff --git a/tools/goctl/api/swagger/swagger.go b/tools/goctl/api/swagger/swagger.go index da100d3e8..0039bbf0b 100644 --- a/tools/goctl/api/swagger/swagger.go +++ b/tools/goctl/api/swagger/swagger.go @@ -1,6 +1,7 @@ package swagger import ( + "encoding/json" "strings" "time" @@ -13,22 +14,23 @@ import ( func spec2Swagger(api *apiSpec.ApiSpec) (*spec.Swagger, error) { extensions, info := specExtensions(api.Info) + var securityDefinitions spec.SecurityDefinitions + securityDefinitionsFromJson := getStringFromKVOrDefault(api.Info.Properties, "securityDefinitionsFromJson", `{}`) + _ = json.Unmarshal([]byte(securityDefinitionsFromJson), &securityDefinitions) swagger := &spec.Swagger{ VendorExtensible: spec.VendorExtensible{ Extensions: extensions, }, SwaggerProps: spec.SwaggerProps{ - Consumes: getListFromInfoOrDefault(api.Info.Properties, "consumes", []string{applicationJson}), - Produces: getListFromInfoOrDefault(api.Info.Properties, "produces", []string{applicationJson}), - Schemes: getListFromInfoOrDefault(api.Info.Properties, "schemes", []string{schemeHttps}), - Swagger: swaggerVersion, - Info: info, - Host: getStringFromKVOrDefault(api.Info.Properties, "host", defaultHost), - BasePath: getStringFromKVOrDefault(api.Info.Properties, "basePath", defaultBasePath), - Paths: spec2Paths(api.Info, api.Service), - SecurityDefinitions: spec.SecurityDefinitions{ - swaggerSecurityDefinitionBearerAuth: spec.APIKeyAuth(swaggerSecurityDefinitionName, swaggerSecurityDefinitionIn), - }, + Consumes: getListFromInfoOrDefault(api.Info.Properties, "consumes", []string{applicationJson}), + Produces: getListFromInfoOrDefault(api.Info.Properties, "produces", []string{applicationJson}), + Schemes: getListFromInfoOrDefault(api.Info.Properties, "schemes", []string{schemeHttps}), + Swagger: swaggerVersion, + Info: info, + Host: getStringFromKVOrDefault(api.Info.Properties, "host", defaultHost), + BasePath: getStringFromKVOrDefault(api.Info.Properties, "basePath", defaultBasePath), + Paths: spec2Paths(api.Info, api.Service), + SecurityDefinitions: securityDefinitions, }, }