Swagger Codegen CLI Java客户端-如何正确使用它

问题描述 投票:14回答:2

我目前正在使用jersey2休息服务。为了更好地了解给定的服务(描述,类型等),我大量使用了swagger(swagger-jersey2-jaxrs)。这样我就可以生成我的服务描述(swagger.json),并且可以通过swagger ui查看和浏览它们。

现在,我需要创建一些客户端以使用这些服务。我来了accrooss swagger codegen cli,这是一个生成客户端和许多不同语言(以Java为例)的好工具。我能够生成正在使用的api客户端和模型。

这里我遇到第一个问题。 REST服务和详细描述受http basic auth保护。我读了documentation,这给了我一些暗示,即可以使用基本身份验证。在这一点上,我不得不指出,从我的角度来看,这种做法非常糟糕。它说:

-a,--auth在远程获取swagger定义时添加授权标头。通过URL编码的name:header字符串,并用逗号分隔多个值。

[我想做的第一件事就是像http标头中那样传递一个字符串,但是那行不通,甚至谷歌搜索如何将基本auth与swagger cli一起使用也没有得到明确的答案。经过大量的尝试和错误后,我(我使用的是CLI 2.1.2)最终遇到了正确的格式,例如:

java -jar swagger-codegen-cli-2.1.2.jar generate -a“授权:基本YWRtaW46YWRtaW4 =” -ihttp://localhost:8080/webproject/restapi/swagger.json-l Java -o restclient

其中,YWRtaW46YWRtaW4 =是我的情况下admin:admin的base64编码值。

到目前为止,一切都很好。生成的Java客户端也必须使用基本身份验证。我看了看ApiClient中的方法,发现了setUsername和setPassword。我认为这种方法使客户端可以使用基本身份验证,但没有运气。

因此,我对生成的类,尤其是ApiClient和几个生成的ApiService类进行了更深入的研究。我发现setUsername和setPassword无效,原因如下:

/**
   * Helper method to set username for the first HTTP basic authentication.
   */
  public void setUsername(String username) {
    for (Authentication auth : authentications.values()) {
      if (auth instanceof HttpBasicAuth) {
        ((HttpBasicAuth) auth).setUsername(username);
        return;
      }
    }
    throw new RuntimeException("No HTTP basic authentication configured!");
  }

同时将HashMap定义如下:

// Setup authentications (key: authentication name, value: authentication).
authentications = new HashMap<String, Authentication>();
// Prevent the authentications from being modified.
authentications = Collections.unmodifiableMap(authentications);

认证哈希图变得不可变,但是为什么呢?用途是什么?此外,ApiClinet内部没有帮助程序方法,该方法可以生成所需的auth对象,因此我做了以下工作:

1)注释掉行身份验证Collections.unmodifiableMap(authentications),以便使哈希图再次变得可修改

2)手动创建所需的身份验证对象

HttpBasicAuth authentication = new HttpBasicAuth(); 
authentication.setUsername("admin");
authentication.setPassword("admin");

3)将auth对象添加到apiClients身份验证哈希图中:

ApiClient apiClient = new ApiClient();
apiClient.setBasePath(basePath);
apiClient.getAuthentications().put("basic", authentication);

4)修改invokeApi方法(ApiClient.java)

public String invokeAPI(String path, String method, Map<String, String> queryParams, Object body, Map<String, String> headerParams, Map<String, String> formParams, String accept, String contentType, String[] authNames) throws ApiException {
String authNames2[] = {"basic"};
updateParamsForAuth(authNames2, queryParams, headerParams);
//updateParamsForAuth(authNames, queryParams, headerParams);
...

步骤4是必需的,因为ApiServices像下面这样调用apiClient方法:

String[] authNames = new String[] {  };
String response = apiClient.invokeAPI(path, "POST", queryParams, postBody, headerParams, formParams, accept, contentType, authNames);

另一种可能的解决方案是在每个apiService中定义身份验证哈希图的Key auf,例如:

String[] authNames = new String[] { "basic" };

完成所有修改后,所有功能均按预期工作,但我无法想到这是自动生成的休息客户端背后的想法。所以我的问题是:我是否遗漏了一点?还是应该考虑一下由swagger生成的客户端(在本例中为Java)更多正在开发的beta解决方案?请让我正确,我认为整个swagger框架(jersey2支持,openapi,swaggerui,codegen)都是很棒的事情,我感谢开发人员的努力,但是我想正确使用codegen,我不认为背后的想法是因此必须以这种方式自定义生成的ApiClient和ApiServices。

java rest swagger swagger-2.0 swagger-codegen
2个回答
12
投票

问题是,您的规范未提及您要使用的安全性类型(也称为安全性定义),或哪种安全性定义适用于哪个端点。

招摇规格是here,但并不能说明全部内容。

您需要做的是1.设置安全性定义。这是一个简单的基本http auth定义:

securityDefinitions:
  basic:
    type: basic
    description: HTTP Basic Authentication. 

并且2.在端点中使用该安全性定义。

paths:
  /:
    get:
      security:
       - basic: []
      responses:
        200:
          description:  OK

然后重新生成您的招摇的客户端代码。它应该正确设置不可变映射和authNames数组。


0
投票

如已经建议的,如果您不想修改现有代码,则可以在自定义配置中扩展ApiClient,例如

@Configuration
public class Config {

  @Value("${baseUrl}")
  private String baseUrl;

  protected class AuthApiClient extends ApiClient {

    public AuthApiClient() {
      super();
    }

    @Override
    public <T> T invokeAPI(final String path, final HttpMethod method,
            final MultiValueMap<String, String> queryParams, final Object body,
            final HttpHeaders headerParams, final MultiValueMap<String, Object> formParams,
            final List<MediaType> accept, final MediaType contentType,
            final String[] authNames, final ParameterizedTypeReference<T> returnType)
            throws RestClientException {

            final HttpBasicAuth auth = new HttpBasicAuth();
            auth.setUsername("myUsername");
            auth.setPassword("myPassword");
            auth.applyToParams(queryParams, headerParams);

      return super.invokeAPI(path, method, queryParams, body, headerParams, formParams,
                accept, contentType, authNames, returnType);
    }
  }

  @Bean
  @Primary
  @Qualifier("MyApiClient")
  public AuthApiClient myApiClient() {
    final AuthApiClient apiClient = new AuthApiClient();
    apiClient.setBasePath(this.baseUrl);
    return apiClient;
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.