Saya baru sahaja mengumumkan kursus Learn Spring Security yang baru, termasuk bahan penuh yang tertumpu pada timbunan OAuth2 baru di Spring Security 5:
>> SEMAK KELUARAN KURSUS TeratasSaya baru sahaja mengumumkan kursus Learn Spring yang baru , yang berfokus pada asas-asas Spring 5 dan Spring Boot 2:
>> SEMAK KURSUS1. Gambaran keseluruhan
Pada masa kini, komponen front-end dan back-end sering memisahkan aplikasi web. Biasanya, kami memperlihatkan API sebagai komponen back-end untuk integrasi komponen front-end atau aplikasi pihak ketiga.
Dalam senario seperti itu, sangat penting untuk mempunyai spesifikasi yang tepat untuk API belakang. Pada masa yang sama, dokumentasi API harus bermaklumat, mudah dibaca, dan mudah diikuti.
Lebih-lebih lagi, dokumentasi rujukan harus menggambarkan secara serentak setiap perubahan dalam API. Menyelesaikan ini secara manual adalah latihan yang membosankan, jadi automasi proses tidak dapat dielakkan.
Dalam tutorial ini, kita akan melihat Swagger 2 untuk perkhidmatan web Spring REST , menggunakan pelaksanaan Springfox spesifikasi Swagger 2.
Sekiranya anda tidak biasa dengan Swagger, kunjungi laman webnya untuk mengetahui lebih lanjut sebelum meneruskan tutorial ini.
2. Projek Sasaran
Pembuatan perkhidmatan REST yang akan kami gunakan bukan dalam ruang lingkup artikel ini. Sekiranya anda sudah mempunyai projek yang sesuai, gunakannya. Sekiranya tidak, pautan ini adalah tempat yang baik untuk memulakan:
- Bina REST API dengan artikel Spring 4 dan Java Config
- Membina Perkhidmatan Web RESTful
3. Menambah Ketergantungan Maven
Seperti disebutkan di atas, kami akan menggunakan implementasi Springfox spesifikasi Swagger. Versi terbaru boleh didapati di Maven Central.
Untuk menambahkannya ke projek Maven kami, kami memerlukan kebergantungan dalam fail pom.xml :
io.springfox springfox-swagger2 2.9.2
3.1. Ketergantungan Spring Boot
Untuk projek berasaskan Spring Boot, cukup untuk menambahkan satu pergantungan springfox-boot-starter :
io.springfox springfox-boot-starter 3.0.0
4. Mengintegrasikan Swagger 2 ke dalam Projek
4.1. Konfigurasi Java
Konfigurasi Swagger berpusat di sekitar kacang Docket :
@Configuration public class SpringFoxConfig { @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.any()) .paths(PathSelectors.any()) .build(); } }
Setelah menentukan Docket bean, metode select () mengembalikan contoh ApiSelectorBuilder , yang menyediakan cara untuk mengawal titik akhir yang didedahkan oleh Swagger.
Kita boleh mengkonfigurasi predikat untuk memilih RequestHandler s dengan bantuan RequestHandlerSelectors dan PathSelectors . Menggunakan mana-mana () untuk kedua-duanya akan menjadikan dokumentasi untuk seluruh API kami tersedia melalui Swagger.
4.2. Konfigurasi Tanpa Spring Boot
Dalam projek Spring biasa, kita perlu mengaktifkan Swagger 2 secara eksplisit. Untuk melakukannya, kita mesti menggunakan @ EnableSwagger2WebMvc pada kelas konfigurasi kami :
@Configuration @EnableSwagger2WebMvc public class SpringFoxConfig { }
Selain itu, tanpa Spring Boot, kami tidak mempunyai konfigurasi automatik pengendali sumber kami.
Swagger UI menambah sekumpulan sumber daya yang mesti kita konfigurasikan sebagai sebahagian daripada kelas yang meluaskan WebMvcConfigurerAdapter dan diberi penjelasan dengan @EnableWebMvc:
@Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("swagger-ui.html") .addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**") .addResourceLocations("classpath:/META-INF/resources/webjars/"); }
4.3. Pengesahan
Untuk mengesahkan bahawa Springfox berfungsi, kami boleh melayari URL ini di penyemak imbas kami:
// localhost: 8080 / spring-security-rest / api / v2 / api-docs
Hasilnya adalah tindak balas JSON dengan sebilangan besar pasangan nilai-kunci, yang tidak begitu mudah dibaca oleh manusia. Nasib baik, Swagger menyediakan Swagger UI untuk tujuan ini.
5. UI Swagger
Swagger UI adalah penyelesaian terpadu yang menjadikan interaksi pengguna dengan dokumentasi API buatan Swagger menjadi lebih mudah.
5.1. Mengaktifkan UI Swagger Springfox
Untuk menggunakan Swagger UI, kita perlu menambahkan pergantungan Maven tambahan:
io.springfox springfox-swagger-ui 2.9.2
Sekarang kita boleh mengujinya di penyemak imbas kita dengan melayari:
// localhost: 8080 / aplikasi-root-swagger-ui /
Dalam kes kami, by the way, URL yang tepat adalah:
// localhost: 8080 / spring-security-rest / api / swagger-ui /
Hasilnya akan kelihatan seperti ini:

5.2. Meneroka Dokumentasi Swagger
Within Swagger’s response is a list of all controllers defined in our application. Clicking on any of them will list the valid HTTP methods (DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT).
Expanding each method provides additional useful data, such as response status, content-type, and a list of parameters. It is also possible to try each method using the UI.
Swagger’s ability to be synchronized with our code base is crucial. To demonstrate this, we can add a new controller to our application:
@RestController public class CustomController { @RequestMapping(value = "/custom", method = RequestMethod.POST) public String custom() { return "custom"; } }
Now if we refresh the Swagger documentation, we see custom-controller in the list of controllers. As we know, there is only one method (POST) shown in Swagger’s response.
6. Spring Data REST
Springfox provides support for Spring Data REST through its springfox-data-rest library.
Spring Boot will take care of the auto-configuration if it discovers the spring-boot-starter-data-rest on the classpath.
Now let's create an entity named User:
@Entity public class User { @Id private Long id; private String firstName; private int age; private String email; // getters and setters }
Then we'll create the UserRepository to add CRUD operations on the User entity:
@Repository public interface UserRepository extends CrudRepository { }
Last, we'll import the SpringDataRestConfiguration class to the SpringFoxConfig class:
@EnableSwagger2WebMvc @Import(SpringDataRestConfiguration.class) public class SpringFoxConfig { //... }
Note: We've used the @EnableSwagger2WebMvc annotation to enable Swagger, as it has replaced the @EnableSwagger2 annotation in version 3 of the libraries.
Let's restart the application to generate the specifications for the Spring Data REST APIs:

We can see that Springfox has generated the specifications for the User entity with HTTP methods like GET, POST, PUT, PATCH, and DELETE.
7. Bean Validations
Springfox also supports the bean validation annotations through its springfox-bean-validators library.
First, we'll add the Maven dependency to our pom.xml:
io.springfox springfox-bean-validators 2.9.2
Again, if we use Spring Boot, we don't have to provide the above dependency explicitly.
Next, let's add a few validation annotations like @NotNull and @Min to the User entity:
@Entity public class User { //... @NotNull(message = "First Name cannot be null") private String firstName; @Min(value = 15, message = "Age should not be less than 15") @Max(value = 65, message = "Age should not be greater than 65") private int age; }
Finally, we'll import the BeanValidatorPluginsConfiguration class to the SpringFoxConfig class:
@EnableSwagger2 @Import(BeanValidatorPluginsConfiguration.class) public class SpringFoxConfig { //... }
Let's take a look at the changes in the API specifications:

Here, we can observe that the User model has * required on the firstName. Also, the minimum and maximum values are defined for the age.
8. Plugin
In order to add specific features to the API specifications, we can create a Springfox plugin. A plugin can offer various features, from enriching the models and properties to the custom API listings and defaults.
Springfox supports the plugin creation through its spi module. The spi module provides a few interfaces like the ModelBuilderPlugin, ModelPropertyBuilderPlugin, and ApiListingBuilderPlugin that act as an extensibility hook to implement a custom plugin.
To demonstrate the capabilities, let's create a plugin to enrich the email property of the User model. We'll use the ModelPropertyBuilderPlugin interface and set the values of the pattern and example.
First, let's create the EmailAnnotationPlugin class and override the supports method to allow any documentation type, such as Swagger 1.2 and Swagger 2:
@Component @Order(Validators.BEAN_VALIDATOR_PLUGIN_ORDER) public class EmailAnnotationPlugin implements ModelPropertyBuilderPlugin { @Override public boolean supports(DocumentationType delimiter) { return true; } }
Then we'll override the apply method of the ModelPropertyBuilderPlugin to set the values of the builder properties:
@Override public void apply(ModelPropertyContext context) { Optional email = annotationFromBean(context, Email.class); if (email.isPresent()) { context.getSpecificationBuilder().facetBuilder(StringElementFacetBuilder.class) .pattern(email.get().regexp()); context.getSpecificationBuilder().example("[email protected]"); } }
So, the API specifications will show the pattern and example values of the property annotated with the @Email annotation.
Next, we'll add the @Email annotation to the User entity:
@Entity public class User { //... @Email(regexp=".*@.*\\..*", message = "Email should be valid") private String email; }
Last, we'll enable the EmailAnnotationPlugin in the SpringFoxConfig class by registering as a bean:
@Import({BeanValidatorPluginsConfiguration.class}) public class SpringFoxConfig { //... @Bean public EmailAnnotationPlugin emailPlugin() { return new EmailAnnotationPlugin(); } }
Let's check out the EmailAnnotationPlugin in action:

We can see the value of the pattern is the same regex (.*@.*\\..*) from the email property of the User entity.
Similarly, the value of the example ([email protected]) is the same, as defined in the apply method of the EmailAnnotationPlugin.
9. Advanced Configuration
The Docket bean of our application can be configured to give us more control over the API documentation generation process.
9.1. Filtering API for Swagger’s Response
It is not always desirable to expose the documentation for the entire API. We can restrict Swagger’s response by passing parameters to the apis() and paths() methods of the Docket class.
As seen above, RequestHandlerSelectors allows using the any or none predicates but can also be used to filter the API according to the base package, class annotation, and method annotations.
PathSelectors provides additional filtering with predicates, which scan the request paths of our application. We can use any(), none(), regex(), or ant().
In the example below, we will instruct Swagger to include only controllers from a particular package, with specific paths, using the ant() predicate:
@Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage("com.baeldung.web.controller")) .paths(PathSelectors.ant("/foos/*")) .build(); }
9.2. Custom Information
Swagger also provides some default values in its response, which we can customize, such as “Api Documentation”, “Created by Contact Email”, and “Apache 2.0”.
To change these values, we can use the apiInfo(ApiInfo apiInfo) method — the ApiInfo class that contains custom information about the API:
@Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage("com.example.controller")) .paths(PathSelectors.ant("/foos/*")) .build() .apiInfo(apiInfo()); } private ApiInfo apiInfo() { return new ApiInfo( "My REST API", "Some custom description of API.", "API TOS", "Terms of service", new Contact("John Doe", "www.example.com", "[email protected]"), "License of API", "API license URL", Collections.emptyList()); }
9.3. Custom Methods Response Messages
Swagger allows globally overriding response messages of HTTP methods through Docket’s globalResponseMessage()method.
First, we need to instruct Swagger not to use default response messages. Suppose we want to override 500 and 403 response messages for all GET methods.
To achieve this, some code must be added to the Docket’s initialization block (original code is excluded for clarity):
.useDefaultResponseMessages(false) .globalResponseMessage(RequestMethod.GET, newArrayList(new ResponseMessageBuilder() .code(500) .message("500 message") .responseModel(new ModelRef("Error")) .build(), new ResponseMessageBuilder() .code(403) .message("Forbidden!") .build()));

10. Swagger UI With an OAuth-Secured API
The Swagger UI provides a number of very useful features that we've covered well so far here. But we can't really use most of these if our API is secured and not accessible.
Let's see how we can allow Swagger to access an OAuth-secured API using the Authorization Code grant type in this example.
We'll configure Swagger to access our secured API using the SecurityScheme and SecurityContext support:
@Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2).select() .apis(RequestHandlerSelectors.any()) .paths(PathSelectors.any()) .build() .securitySchemes(Arrays.asList(securityScheme())) .securityContexts(Arrays.asList(securityContext())); }
10.1. The Security Configuration
We'll define a SecurityConfiguration bean in our Swagger configuration and set some defaults:
@Bean public SecurityConfiguration security() { return SecurityConfigurationBuilder.builder() .clientId(CLIENT_ID) .clientSecret(CLIENT_SECRET) .scopeSeparator(" ") .useBasicAuthenticationWithAccessCodeGrant(true) .build(); }
10.2. SecurityScheme
Next, we'll define our SecurityScheme; this is used to describe how our API is secured (Basic Authentication, OAuth2, …).
In our case here, we'll define an OAuth scheme used to secure our Resource Server:
private SecurityScheme securityScheme() { GrantType grantType = new AuthorizationCodeGrantBuilder() .tokenEndpoint(new TokenEndpoint(AUTH_SERVER + "/token", "oauthtoken")) .tokenRequestEndpoint( new TokenRequestEndpoint(AUTH_SERVER + "/authorize", CLIENT_ID, CLIENT_SECRET)) .build(); SecurityScheme oauth = new OAuthBuilder().name("spring_oauth") .grantTypes(Arrays.asList(grantType)) .scopes(Arrays.asList(scopes())) .build(); return oauth; }
Note that we used the Authorization Code grant type, for which we need to provide a token endpoint and the authorization URL of our OAuth2 Authorization Server.
And here are the scopes we need to have defined:
private AuthorizationScope[] scopes() { AuthorizationScope[] scopes = { new AuthorizationScope("read", "for read operations"), new AuthorizationScope("write", "for write operations"), new AuthorizationScope("foo", "Access foo API") }; return scopes; }
These sync up with the scopes we actually have defined in our application, for the /foos API.
10.3. SecurityContext
Finally, we need to define a SecurityContext for our example API:
private SecurityContext securityContext() { return SecurityContext.builder() .securityReferences( Arrays.asList(new SecurityReference("spring_oauth", scopes()))) .forPaths(PathSelectors.regex("/foos.*")) .build(); }
Note how the name we used here in the reference — spring_oauth — syncs up with the name we used previously in the SecurityScheme.
10.4. Test
Now that we have everything set up and ready to go, let's take a look at our Swagger UI and try access the Foo API.
We can access the Swagger UI locally:
//localhost:8082/spring-security-oauth-resource/swagger-ui.html
As we can see, a new Authorize button now exists due to our security configurations:

When we click the Authorize button, we can see the following pop-up to authorize our Swagger UI to access the secured API:

Note that:
- We can already see the CLIENT_ID and CLIENT_SECRET, as we've pre-configured them earlier (but we can still change them).
- We can now select the scopes we need.
Here's how the secured API is marked:

And now, finally, we can hit our API!
Sudah tentu, hampir tidak perlu dikatakan bahawa kita harus berhati-hati bagaimana kita memaparkan Swagger UI secara luaran, sekarang apabila konfigurasi keselamatan ini aktif.
11. Kesimpulannya
Dalam artikel ini, kami menyiapkan Swagger 2 untuk menghasilkan dokumentasi untuk Spring REST API. Kami juga meneroka cara untuk memvisualisasikan dan menyesuaikan output Swagger. Dan akhirnya, kami melihat konfigurasi OAuth yang mudah untuk Swagger.
The pelaksanaan penuh tutorial ini boleh didapati dalam projek GitHub itu. Untuk melihat persediaan dalam projek Boot, periksa modul GitHub ini.
Untuk bahagian OAuth, kod tersebut terdapat di repositori spring-security-oauth kami.
Dan jika anda pelajar REST With Spring, pergi ke Pelajaran 1 dari Modul 7 untuk menyelami penyediaan Swagger dengan Spring and Spring Boot.
Bahagian bawah keselamatan