Swagger 2 instellen met een Spring REST API

Beveiliging Top

Ik heb zojuist de nieuwe Learn Spring Security-cursus aangekondigd, inclusief het volledige materiaal gericht op de nieuwe OAuth2-stack in Spring Security 5:

>> BEKIJK DE CURSUS REST Top

Ik heb zojuist het nieuwe aangekondigd Leer de lente natuurlijk, gericht op de basisprincipes van Spring 5 en Spring Boot 2:

>> BEKIJK DE CURSUS

1. Overzicht

Tegenwoordig scheiden front-end en back-end componenten vaak een webapplicatie. Meestal stellen we API's bloot als een back-endcomponent voor de front-endcomponent of app-integraties van derden.

In een dergelijk scenario is het essentieel om de juiste specificaties voor de back-end API's te hebben. Tegelijkertijd moet de API-documentatie informatief, leesbaar en gemakkelijk te volgen zijn.

Bovendien moet referentiedocumentatie elke wijziging in de API gelijktijdig beschrijven. Dit handmatig uitvoeren is een vervelende bezigheid, dus automatisering van het proces was onvermijdelijk.

In deze tutorial zullen we kijken naar Swagger 2 voor een Spring REST-webservice, met behulp van de Springfox-implementatie van de Swagger 2-specificatie.

Als u niet bekend bent met Swagger, bezoek dan de webpagina voor meer informatie voordat u verdergaat met deze zelfstudie.

2. Doelproject

Het maken van de REST-service die we zullen gebruiken, valt niet binnen het bestek van dit artikel. Als je al een geschikt project hebt, maak er dan gebruik van. Zo niet, dan zijn deze links een goede plek om te beginnen:

  • Bouw een REST API met Spring 4 en Java Config-artikel
  • Bouwen aan een RESTful Web Service

3. De afhankelijkheid van Maven toevoegen

Zoals hierboven vermeld, zullen we de Springfox-implementatie van de Swagger-specificatie gebruiken. De nieuwste versie is te vinden op Maven Central.

Om het aan ons Maven-project toe te voegen, hebben we een afhankelijkheid nodig in het pom.xml het dossier:

 io.springfox springfox-swagger2 2.9.2 

3.1. Afhankelijkheid van Spring Boot

Voor de Spring Boot-gebaseerde projecten, het is genoeg om er een toe te voegen springfox-boot-starter afhankelijkheid:

 io.springfox springfox-boot-starter 3.0.0 

4. Swagger 2 integreren in het project

4.1. Java-configuratie

De configuratie van Swagger draait voornamelijk om het Docket Boon:

@Configuratie openbare klasse SpringFoxConfig {@Bean openbare Docket api () {retourneer nieuwe Docket (DocumentationType.SWAGGER_2) .select () .apis (RequestHandlerSelectors.any ()) .paths (PathSelectors.any ()) .build (); }}

Na het definiëren van de Docket boon, zijn selecteer () methode retourneert een instantie van ApiSelectorBuilder, die een manier biedt om de eindpunten te beheren die door Swagger worden weergegeven.

We kunnen predikaten configureren om te selecteren RequestHandlers met behulp van RequestHandlerSelectors en PathSelectors. Gebruik makend van ieder() want beide zullen documentatie voor onze gehele API beschikbaar stellen via Swagger.

4.2. Configuratie zonder Spring Boot

In gewone Spring-projecten moeten we Swagger 2 expliciet inschakelen. Om dit te doen, we moeten de @ EnableSwagger2WebMvc op onze configuratieklasse:

@Configuration @ EnableSwagger2WebMvc openbare klasse SpringFoxConfig {}

Bovendien hebben we zonder Spring Boot niet de luxe van automatische configuratie van onze resource-handlers.

Swagger UI voegt een set bronnen toe die we moeten configureren als onderdeel van een klasse die zich uitbreidt WebMvcConfigurerAdapter en is geannoteerd met @EnableWebMvc:

@Override public void addResourceHandlers (register ResourceHandlerRegistry) {registry.addResourceHandler ("swagger-ui.html") .addResourceLocations ("classpath: / META-INF / resources /"); registry.addResourceHandler ("/ webjars / **") .addResourceLocations ("classpath: / META-INF / resources / webjars /"); }

4.3. Verificatie

Om te verifiëren dat Springfox werkt, kunnen we deze URL in onze browser bezoeken:

// localhost: 8080 / spring-security-rest / api / v2 / api-docs

Het resultaat is een JSON-antwoord met een groot aantal sleutel-waardeparen, dat niet erg leesbaar is voor mensen. Gelukkig biedt Swagger Swagger UI Voor dit doeleinde.

5. Swagger UI

Swagger UI is een ingebouwde oplossing die gebruikersinteractie met de door Swagger gegenereerde API-documentatie veel eenvoudiger maakt.

5.1. De Swagger UI van Springfox inschakelen

Om Swagger UI te gebruiken, moeten we een extra Maven-afhankelijkheid toevoegen:

 io.springfox springfox-swagger-ui 2.9.2 

Nu kunnen we het in onze browser testen door naar:

// localhost: 8080 / uw-app-root / swagger-ui /

In ons geval is de exacte URL trouwens:

// localhost: 8080 / spring-security-rest / api / swagger-ui /

Het resultaat zou er ongeveer zo uit moeten zien:

5.2. Swagger-documentatie verkennen

Binnen Swaggers antwoord is een lijst met alle controllers gedefinieerd in onze applicatie. Als u op een van deze klikt, worden de geldige HTTP-methoden weergegeven (VERWIJDEREN, KRIJGEN, HOOFD, OPTIES, PATCH, POST, LEGGEN).

Het uitbreiden van elke methode levert aanvullende nuttige gegevens op, zoals antwoordstatus, inhoudstype en een lijst met parameters. Het is ook mogelijk om elke methode uit te proberen met behulp van de gebruikersinterface.

Het vermogen van Swagger om te worden gesynchroniseerd met onze codebasis is cruciaal. Om dit aan te tonen kunnen we een nieuwe controller aan onze applicatie toevoegen:

@RestController openbare klasse CustomController {@RequestMapping (value = "/ custom", method = RequestMethod.POST) openbare String custom () {return "custom"; }}

Als we nu de Swagger-documentatie vernieuwen, zien we aangepaste controller in de lijst met controllers. Zoals we weten, is er maar één methode (POST) weergegeven in de reactie van Swagger.

6. Veergegevens REST

Springfox biedt ondersteuning voor Spring Data REST via zijn springfox-data-rest bibliotheek.

Spring Boot zorgt voor de automatische configuratie als het het spring-boot-starter-data-rest op het klassenpad.

Laten we nu een entiteit maken met de naam Gebruiker:

@Entity openbare klasse Gebruiker {@Id privé Lange id; private String voornaam; privé int leeftijd; privé String-e-mail; // getters en setters}

Vervolgens maken we het UserRepository om CRUD-bewerkingen toe te voegen aan het Gebruiker entiteit:

@Repository openbare interface UserRepository breidt CrudRepository uit {}

Als laatste importeren we het SpringDataRestConfiguration klasse naar de SpringFoxConfig klasse:

@ EnableSwagger2WebMvc @Import (SpringDataRestConfiguration.class) openbare klasse SpringFoxConfig {// ...}

Opmerking: we hebben de @ EnableSwagger2WebMvc annotatie om Swagger in te schakelen, aangezien het de @ EnableSwagger2 annotatie in versie 3 van de bibliotheken.

Laten we de applicatie opnieuw starten om de specificaties voor de Spring Data REST API's te genereren:

We kunnen zien dat Springfox de specificaties voor het Gebruiker entiteit met HTTP-methoden zoals KRIJGEN, POST, ZET, PATCH, en VERWIJDEREN.

7. Validaties van bonen

Springfox ondersteunt ook de annotaties van bean-validatie via zijn springfox-bean-validators bibliotheek.

Eerst voegen we de Maven-afhankelijkheid toe aan onze pom.xml:

 io.springfox springfox-bean-validators 2.9.2 

Opnieuw, als we Spring Boot gebruiken, hoeven we de bovenstaande afhankelijkheid niet expliciet op te geven.

Laten we vervolgens een paar validatie-annotaties toevoegen, zoals @Niet nul en @Min naar de Gebruiker entiteit:

@Entity openbare klasse Gebruiker {// ... @NotNull (bericht = "Voornaam mag niet null zijn") private String firstName; @Min (waarde = 15, bericht = "Leeftijd mag niet lager zijn dan 15") @Max (waarde = 65, bericht = "Leeftijd mag niet hoger zijn dan 65") private int leeftijd; }

Ten slotte importeren we het BeanValidatorPluginsConfiguration klasse naar de SpringFoxConfig klasse:

@ EnableSwagger2 @Import (BeanValidatorPluginsConfiguration.class) openbare klasse SpringFoxConfig {// ...}

Laten we eens kijken naar de wijzigingen in de API-specificaties:

Hier kunnen we zien dat de Gebruiker model heeft * verplicht op de Voornaam. Ook de minimum en maximum waarden zijn gedefinieerd voor de leeftijd.

8. Plug-in

Om specifieke functies aan de API-specificaties toe te voegen, kunnen we een Springfox-plug-in maken. Een plug-in kan verschillende functies bieden, van het verrijken van de modellen en eigenschappen tot de aangepaste API-lijsten en standaardinstellingen.

Springfox ondersteunt het maken van plug-ins via zijn spi-module. De spi-module biedt een aantal interfaces zoals de ModelBuilderPlugin, ModelPropertyBuilderPlugin, en ApiListingBuilderPlugin die fungeren als een uitbreidingshaak om een ​​aangepaste plug-in te implementeren.

Laten we, om de mogelijkheden te demonstreren, een plug-in maken om het e-mail eigendom van de Gebruiker model. We gebruiken de ModelPropertyBuilderPlugin interface en stel de waarden van de patroon en voorbeeld.

Laten we eerst het EmailAnnotationPlugin class en overschrijf de ondersteunt methode om elk documentatietype toe te staan, zoals Swagger 1.2 en Swagger 2:

@Component @Order (Validators.BEAN_VALIDATOR_PLUGIN_ORDER) openbare klasse EmailAnnotationPlugin implementeert ModelPropertyBuilderPlugin {@Override openbare booleaanse ondersteuning (DocumentationType-scheidingsteken) {return true; }}

Dan overschrijven we de van toepassing zijn methode van de ModelPropertyBuilderPlugin om de waarden van de builder-eigenschappen in te stellen:

@Override public void apply (ModelPropertyContext-context) {Optioneel email = annotationFromBean (context, Email.class); if (email.isPresent ()) {context.getSpecificationBuilder (). facetBuilder (StringElementFacetBuilder.class) .pattern (email.get (). regexp ()); context.getSpecificationBuilder (). voorbeeld ("[e-mail beveiligd]"); }}

De API-specificaties tonen dus de patroon en voorbeeld waarden van de eigenschap geannoteerd met de @E-mail annotatie.

Vervolgens voegen we de @E-mail annotatie bij de Gebruiker entiteit:

@Entity openbare klasse Gebruiker {// ... @Email (regexp = ". * @. * \ .. *", message = "E-mail moet geldig zijn") privé String-e-mail; }

Als laatste schakelen we het EmailAnnotationPlugin in de SpringFoxConfig les door te registreren als boon:

@Import ({BeanValidatorPluginsConfiguration.class}) openbare klasse SpringFoxConfig {// ... @Bean openbare EmailAnnotationPlugin emailPlugin () {retourneer nieuwe EmailAnnotationPlugin (); }}

Laten we eens kijken naar de EmailAnnotationPlugin in actie:

We kunnen de waarde van de patroon is dezelfde regex (. * @. * \ .. *) uit het e-mail eigendom van de Gebruiker entiteit.

Evenzo is de waarde van de voorbeeld ([email protected]) is hetzelfde, zoals gedefinieerd in het van toepassing zijn methode van de EmailAnnotationPlugin.

9. Geavanceerde configuratie

De Docket bean van onze applicatie kan worden geconfigureerd om ons meer controle te geven over het proces voor het genereren van API-documentatie.

9.1. Filter-API voor de reactie van Swagger

Het is niet altijd wenselijk om de documentatie voor de hele API vrij te geven. We kunnen de reactie van Swagger beperken door parameters door te geven aan de api's () en paden () methoden van de Docket klasse.

Zoals hierboven te zien is, RequestHandlerSelectors maakt het gebruik van de ieder of geen predikaten, maar kan ook worden gebruikt om de API te filteren op basis van het basispakket, klasseannotatie en methodeannotaties.

PathSelectors biedt extra filtering met predikaten, die de verzoekpaden van onze applicatie scannen. We kunnen gebruiken ieder(), geen(), regex (), of mier().

In het onderstaande voorbeeld zullen we Swagger instrueren om alleen controllers uit een bepaald pakket, met specifieke paden, op te nemen met behulp van de mier() predikaat:

@Bean public Docket api () {retourneer nieuwe Docket (DocumentationType.SWAGGER_2) .select () .apis (RequestHandlerSelectors.basePackage ("com.baeldung.web.controller")) .paths (PathSelectors.ant ("/ foos / * ")) .build (); }

9.2. Aangepaste informatie

Swagger biedt ook enkele standaardwaarden in zijn antwoord, die we kunnen aanpassen, zoals "Api-documentatie", "Gemaakt door e-mail contactpersoon" en "Apache 2.0".

Om deze waarden te wijzigen, kunnen we de apiInfo (ApiInfo apiInfo) methode - de ApiInfo klasse die aangepaste informatie over de API bevat:

@Bean public Docket api () {retourneer nieuwe Docket (DocumentationType.SWAGGER_2) .select () .apis (RequestHandlerSelectors.basePackage ("com.example.controller")) .paths (PathSelectors.ant ("/ foos / *") ) .build () .apiInfo (apiInfo ()); } private ApiInfo apiInfo () {retourneer nieuwe ApiInfo ("Mijn REST API", "Een aangepaste beschrijving van de API.", "API TOS", "Servicevoorwaarden", nieuwe contactpersoon ("John Doe", "www.example. com "," [e-mailbeveiligd] ")," API-licentie "," API-licentie-URL ", Collections.emptyList ()); }

9.3. Aangepaste methoden antwoordberichten

Swagger staat toe wereldwijd vervangende antwoordberichten van HTTP-methoden door Docket’S globalResponseMessage ()methode.

Ten eerste moeten we Swagger instrueren om geen standaardantwoordberichten te gebruiken. Stel dat we het willen overschrijven 500 en 403 antwoordberichten voor iedereen KRIJGEN methoden.

Om dit te bereiken, moet wat code worden toegevoegd aan het DocketInitialisatieblokkering (originele code is voor de duidelijkheid uitgesloten):

.useDefaultResponseMessages (false) .globalResponseMessage (RequestMethod.GET, newArrayList (new ResponseMessageBuilder () .code (500) .message ("500 message") .responseModel (new ModelRef ("Error")) .build (), nieuwe ResponseMessageBuilder ( ) .code (403) .message ("Verboden!") .build ()));

10. Swagger UI met een OAuth-beveiligde API

De gebruikersinterface van Swagger biedt een aantal zeer nuttige functies die we hier tot nu toe goed hebben behandeld. Maar we kunnen de meeste hiervan niet echt gebruiken als onze API beveiligd en niet toegankelijk is.

Laten we eens kijken hoe we Swagger toegang kunnen geven tot een OAuth-beveiligde API met behulp van het toekenningstype Autorisatiecode in dit voorbeeld.

We zullen Swagger configureren om toegang te krijgen tot onze beveiligde API met behulp van de Beveiligingsschema en SecurityContext ondersteuning:

@Bean public Docket api () {retourneer nieuwe Docket (DocumentationType.SWAGGER_2) .select () .apis (RequestHandlerSelectors.any ()) .paths (PathSelectors.any ()) .build () .securitySchemes (Arrays.asList (securityScheme ())) .securityContexts (Arrays.asList (securityContext ())); }

10.1. De beveiligingsconfiguratie

We zullen een SecurityConfiguration bean in onze Swagger-configuratie en stel enkele standaardinstellingen in:

@Bean public SecurityConfiguration security () {retourneer SecurityConfigurationBuilder.builder () .clientId (CLIENT_ID) .clientSecret (CLIENT_SECRET) .scopeSeparator ("") .useBasicAuthenticationWithAccessCodeGrant (true) .build (); }

10.2. Beveiligingsschema

Vervolgens definiëren we onze Beveiligingsschema; dit wordt gebruikt om te beschrijven hoe onze API is beveiligd (Basic Authentication, OAuth2,…).

In ons geval zullen we hier een OAuth-schema definiëren dat wordt gebruikt om onze Resource Server te beveiligen:

private SecurityScheme securityScheme () {GrantType grantType = nieuwe AuthorizationCodeGrantBuilder () .tokenEndpoint (nieuw TokenEndpoint (AUTH_SERVER + "/ token", "oauthtoken")) .tokenRequestEndpoint (nieuw TokenRequestEndpoint (AUTH_SERVER + "/). bouwen(); SecurityScheme oauth = nieuwe OAuthBuilder (). Naam ("spring_oauth") .grantTypes (Arrays.asList (grantType)) .scopes (Arrays.asList (scopes ())) .build (); terugkeer oauth; }

Merk op dat we het toekenningstype Autorisatiecode hebben gebruikt, waarvoor we een tokeneindpunt en de autorisatie-URL van onze OAuth2-autorisatieserver moeten opgeven.

En hier zijn de bereiken die we moeten hebben gedefinieerd:

private AuthorizationScope [] scopes () {AuthorizationScope [] scopes = {nieuwe AuthorizationScope ("read", "voor leesbewerkingen"), nieuwe AuthorizationScope ("write", "voor schrijfbewerkingen"), nieuwe AuthorizationScope ("foo", " Toegang tot foo API ")}; bereik teruggeven; }

Deze worden gesynchroniseerd met de bereiken die we feitelijk in onze applicatie hebben gedefinieerd, voor de / foos API.

10.3. SecurityContext

Ten slotte moeten we een SecurityContext voor onze voorbeeld-API:

private SecurityContext securityContext () {retourneer SecurityContext.builder () .securityReferences (Arrays.asList (nieuwe SecurityReference ("spring_oauth", scopes ()))) .forPaths (PathSelectors.regex ("/ foos. *")) .build ( ); }

Merk op hoe de naam die we hier in de referentie hebben gebruikt - spring_oauth - wordt gesynchroniseerd met de naam die we eerder gebruikten in het Beveiligingsschema.

10.4. Test

Nu we alles hebben ingesteld en klaar voor gebruik, kunnen we eens kijken naar onze Swagger UI en proberen toegang te krijgen tot de Foo API.

We hebben lokaal toegang tot de gebruikersinterface van Swagger:

//localhost:8082/spring-security-oauthathedral/swagger-ui.html

Zoals we kunnen zien, bestaat er nu een nieuwe autorisatieknop vanwege onze beveiligingsconfiguraties:

Wanneer we op de knop Autoriseren klikken, zien we de volgende pop-up om onze Swagger-gebruikersinterface te autoriseren om toegang te krijgen tot de beveiligde API:

Let daar op:

  • We kunnen de CLIENT_ID en CLIENT_SECRET al zien, zoals we ze eerder hebben geconfigureerd (maar we kunnen ze nog steeds wijzigen).
  • We kunnen nu de scopes selecteren die we nodig hebben.

Hier is hoe de beveiligde API is gemarkeerd:

En nu kunnen we eindelijk onze API gebruiken!

Het is natuurlijk bijna vanzelfsprekend dat we voorzichtig moeten zijn hoe we de Swagger UI extern tonen, nu deze beveiligingsconfiguratie actief is.

11. Conclusie

In dit artikel hebben we Swagger 2 ingesteld om documentatie voor een Spring REST API te genereren. We hebben ook manieren onderzocht om de output van Swagger te visualiseren en aan te passen. En tot slot hebben we gekeken naar een eenvoudige OAuth-configuratie voor Swagger.

De volledige implementatie van deze tutorial is te vinden in het GitHub-project. Bekijk deze GitHub-module om de setup in een Boot-project te zien.

Voor de OAuth-sectie is de code beschikbaar in onze spring-security-oauth-repository.

En als je een student bent van REST With Spring, ga dan naar les 1 van module 7 voor een diepe duik in het opzetten van Swagger met Spring en Spring Boot.

Beveiligingsbodem

Ik heb zojuist de nieuwe Learn Spring Security-cursus aangekondigd, inclusief het volledige materiaal gericht op de nieuwe OAuth2-stack in Spring Security 5:

>> BEKIJK DE CURSUS REST onder

Ik heb zojuist het nieuwe aangekondigd Leer de lente natuurlijk, gericht op de basisprincipes van Spring 5 en Spring Boot 2:

>> BEKIJK DE CURSUS