2016-09-27 8 views
10

Ich spiele gerade mit meinem jersey2 Rest Service herum. Für einen besseren Überblick über den gegebenen Dienst (Beschreibung, Typen usw.) verwende ich stark swagger (swagger-jersey2-jaxrs). So kann ich meine Service-Beschreibung (swagger.json) generieren und ich kann sie über swagger ui anzeigen und erkunden.Swagger Codegen CLI Java Client - Wie man es richtig benutzt

Jetzt bin ich an dem Punkt, dass ich einige Clients erstellen muss, um diese Dienste zu nutzen. Ich kam accooss Swagger Codegen CLI, die ein nettes Werkzeug ist, um Ihren Kunden und viele verschiedene Sprachen zu generieren (Java in meinem Fall). Ich kann den API-Client und das verwendete Modell generieren.

Hier kam ich über das erste Problem. Die REST-Dienste und die Swagger-Beschreibung sind http-basic-auth-geschützt. Ich lese die documentation, die mir einen Hinweis gab, dass es eine Möglichkeit gibt, grundlegende Auth zu verwenden. An dieser Stelle muss ich erwähnen, dass die Doucmentation aus meiner Sicht sehr schlecht ist. Sie lautet:

-a, --auth fügt Autorisierungsheader hinzu, wenn die Swagger-Definitionen remote abgerufen werden. Geben Sie eine URL-codierte Zeichenfolge name: header mit einem Komma ein, das mehrere Werte voneinander trennt.

Das erste, was ich thoght von ist, eine Zeichenfolge wie in einem HTTP-Header übergeben, aber das nicht funktionieren und sogar googeln, wie die Verwendung von Basic Auth mit Swagger CLI führte nicht zu einigen klaren Antworten. Nach vielen Versuchen und Fehlern (ich benutze CLI 2.1.2) kam ich schließlich über das richtige Format, zB:

java -jar swagger-codegen-cli-2.1.2.jar erzeugen -a " Authorization: Grund YWRtaW46YWRtaW4 =“-i http://localhost:8080/webproject/restapi/swagger.json -l java -o

restclient

wo YWRtaW46YWRtaW4 = den die base64-codierte Wert admin: admin in meinem Fall.

So weit so gut. Der generierte Java-Client muss auch Basic Auth verwenden. Ich habe mir die Methoden aus dem ApiClient angeschaut und setUsername und setPassword gefunden. Ich dachte, dass diese Methode den Klienten dazu befähigt, Grundkenntnisse zu verwenden, aber kein Glück.

Also habe ich mir die generierten Klassen genauer angeschaut, insbesondere den ApiClient und die verschiedenen generierten ApiService Klassen. Ich fand heraus, dass die setUsername und setPassword keine Wirkung haben aus folgendem Grund:

/** 
    * 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!"); 
    } 

wo zugleich die HashMap wie folgt definiert ist:

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

Die Authentifizierungs hashmap wird unveränderlich, aber warum? Was ist der Zweck? Weiterhin gibt es keine Hilfsmethoden innerhalb des ApiClinet die das benötigten auth Objekt erzeugt, so habe ich das follwing:

1) die Zeile Authentifizierungen Collections.unmodifiableMap auf Kommentar (Authentifizierungen), so dass die modifizierbare hashmap wird wieder

2) benötigte auth Objekt erstellen manualy

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

3) fügen Sie das auth Objekt zu dem Authentifizierungs apiClients hashmap:

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

4) Ändern der Methode 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); 
... 

Schritt 4 ist notwendig, weil die Apiservices der apiClient Verfahren wie die folgenden aufzurufen:

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

Eine andere mögliche Lösung wäre, die Schlüssel auf der Authentifizierungen hashmap in jedem apiService zu definieren, wie:

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

Nachdem alle Änderungen tun alles wie erwartet funktioniert, aber ich kann nicht denken, dass dies die Idee hinter einem automatisch generierten Rest-Client. Also meine Frage ist: Verpasse ich einen Punkt oder sollte ich an den von swagger generierten Client denken (Java in diesem Fall) eher eine Beta-Lösung, die gerade entwickelt wird? Bitte gib mir Recht, ich denke, das ganze Swagger-Framework (jersey2-Unterstützung, openapi, swaggerui, codegen) ist eine großartige Sache und ich schätze die Entwickler-Bemühungen, aber ich möchte den Codegen richtig nutzen und ich denke nicht, dass die Idee dahinter steht muss also den generierten ApiClient und ApiServices so anpassen.

Antwort

8

Das Problem besteht darin, dass in Ihrer Spezifikation nicht angegeben ist, welche Sicherheitstypen Sie verwenden möchten (z. B. Sicherheitsdefinitionen) oder welche Sicherheitsdefinition für welchen Endpunkt gilt.

Die Swagger-Spezifikation ist here, aber es erzählt nicht die ganze Geschichte.

Was Sie tun müssen, ist 1. Richten Sie die Sicherheitsdefinitionen ein. Hier ist eine einfache grundlegende HTTP-Auth-Definition:

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

und 2. Verwenden Sie diese Sicherheitsdefinition im Endpunkt.

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

Dann generieren Sie Ihren Swagger-Client-Code neu. Es sollte die immutable map korrekt und das authNames-Array einrichten.

Verwandte Themen