当前位置: 首页 > 知识库问答 >
问题:

Swagger Codigen CLIJava客户端-如何正确使用它

邵劲
2023-03-14

我目前正在玩我的球衣Rest服务。为了更好地概述给定的服务(描述、类型等),我大量使用了swagger(swagger-jersey2-jaxrs)。因此,我能够生成我的服务描述(swagger.json),我可以通过swagger ui查看和探索它们。

现在我需要创建一些客户机来使用这些服务。我遇到了swagger codegen cli,它是一个很好的工具,可以生成您的客户端和许多不同的语言(在我的例子中是java)。我能够生成api客户端和正在使用的模型。

这里我面临第一个问题。REST服务和swagger描述受http基本身份验证保护。我阅读了一些文档,这些文档给了我一些提示,说明可以使用basicauth。在这一点上,我必须提到,从我的观点来看,文档非常糟糕。它说:

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

我首先想到的是传递一个类似于超文本传输协议头的字符串,但这并不起作用,甚至谷歌搜索如何使用基本身份验证和昂首阔步的cli也没有得到一些明确的答案。经过大量的尝试和错误,我(我使用CLI 2.1.2)终于遇到了正确的格式:

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

其中YWRtaW46YWRtaW4=在我的例子中是admin:admin的base64编码值。

到现在为止,一直都还不错。生成的java客户端还必须使用基本身份验证。我查看了ApiClient中的方法,找到了setUsername和setPassword。我认为这种方法使客户端能够使用基本的auth,但没有运气。

因此,我深入研究了生成的类,特别是ApicClient和几个生成的ApisService类。我发现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) 注释掉行身份验证集合。不可修改的映射(身份验证),因此哈希映射再次变得可修改

2)手动创建需要的auth对象

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);

另一种可能的解决方案是在每个API服务中定义authentications hashmap的密钥,如:

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

在做了所有的修改之后,一切都按照预期工作,但我认为这不是自动生成的rest客户机背后的想法。所以我的问题是:我是否遗漏了一些要点,或者我是否应该将swagger生成的客户机(在本例中为java)看作是一个正在开发的测试版解决方案?请正确地理解我,我认为整个swagger框架(jersey2支持、openapi、swaggerui、codegen)是一件很棒的事情,我感谢开发人员的努力,但我想正确地使用codegen,我不认为背后的想法是必须以这种方式定制生成的ApiClient和ApiServices。

共有2个答案

冯元魁
2023-03-14

如前所述,如果您不想修改现有代码,您可以在自定义配置中扩展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;
  }
}
公冶浩慨
2023-03-14

问题是您的规范没有提到要使用的安全类型(又名。安全定义)或哪个安全定义适用于哪个终端。

昂首阔步的规范在这里,但它并没有讲述整个故事。

你需要做的是1。设置安全性定义。下面是一个简单的基本http身份验证定义:

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

二,。在endpoint中使用该安全性定义。

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

然后重新生成你昂首阔步的客户端代码。它应该正确设置不可变映射和autNames数组。

 类似资料:
  • 问题内容: 所有,我都试图编写一个在Axis2.1.5中调用Web Service客户端的Junit测试,而对于如何准确地将其设置为使用WS- Addressing感到困惑。 我已经使用wsdl2java生成了一个客户端存根,并且正在使用axis2二进制发行版中的axis2.xml和模块存储库。 我知道我需要使用WS-Addressing的MemberSubmission版本,并且我 认为 我已经

  • 问题内容: 我正在使用Java开发RESTful Web服务。如果出现问题,我需要一种将错误消息发送给客户端的好方法。 根据Javadoc的规定, “由于message参数含义不明确 ,因此不建议使用 ”。 有没有设置状态消息或响应的“ 原因短语 ”的首选方法?该方法不这样做。 编辑:为了澄清,我想修改HTTP状态行,即不是主体内容。具体来说,我想发送类似的回复。 问题答案: 我认为任何RESTf

  • 问题内容: 我正在建立一个使用RESTful API(Jersey)的AngularJS网络应用程序。 在服务器端,我正在使用Java应用程序服务器(详细来说是Glassfish 4)。 我的设置如下: AngularJS Webapp作为单个war文件部署到Java EE应用程序服务器。 RESTfulAPI(和后端逻辑)也作为war文件部署到同一Java EE应用程序服务器。 AngularJ

  • 我尝试为我的网站提供文件上传/下载服务,并且尝试使用openstack中的对象存储。问题是,我通过php和openstack PHPSDK做这件事没有问题,但是当我试图通过一些javascript做这件事时,我找不到一个好的sdk或方法。我没有使用node,我有一个php服务器和一个javascript客户端。我想直接从javascript客户端上传或下载文件。我不希望文件通过php服务器传输。我

  • 问题内容: 所以我试图学习选项SO_KEEPALIVE在Linux环境下用C语言进行套接字编程中的用法。 我创建了一个服务器套接字,并使用浏览器连接到它。它成功完成了,我能够读取GET请求,但是我对SO_KEEPALIVE的使用感到困惑。 我检查了此链接keepalive_description@tldg.org,但找不到任何示例来说明如何使用它。 一旦我检测到客户端对功能的请求,便在客户端套接字

  • 问题内容: 我正在尝试使用Akka HTTP 2.0-M2编写用于批量数据上传的工具。但是我面对 我试图找出问题,但以下示例代码也失败了: 它失败并显示: 我猜那是因为我试图创建很多期货并立即执行它们。但是Akka不应该启用背压吗?我想我用错了。我尝试了superPool方法,但没有做任何更改,因为据我了解,内部具有相同的池。我也尝试重用Http实例而不是在循环中调用,但这也无济于事。 触发一批请