How to enable "Authorize" button in springdoc-openapi-ui (OpenAPI 3.0 /swagger-ui.html
) for Bearer Token Authentication, for example JWT.
What annotations have to be added to Spring @Controller
and @Configuration
classes?
How to enable "Authorize" button in springdoc-openapi-ui (OpenAPI 3.0 /swagger-ui.html
) for Bearer Token Authentication, for example JWT.
What annotations have to be added to Spring @Controller
and @Configuration
classes?
I prefer to use bean initialization instead of annotation.
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
@Configuration
public class OpenApi30Config {
private final String moduleName;
private final String apiVersion;
public OpenApi30Config(
@Value("${module-name}") String moduleName,
@Value("${api-version}") String apiVersion) {
this.moduleName = moduleName;
this.apiVersion = apiVersion;
}
@Bean
public OpenAPI customOpenAPI() {
final String securitySchemeName = "bearerAuth";
final String apiTitle = String.format("%s API", StringUtils.capitalize(moduleName));
return new OpenAPI()
.addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
.components(
new Components()
.addSecuritySchemes(securitySchemeName,
new SecurityScheme()
.name(securitySchemeName)
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")
)
)
.info(new Info().title(apiTitle).version(apiVersion));
}
}
The line of code
.addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
allows to add global security schema and to get rid of writing security to each @Operation of method.
Define a global security scheme for OpenAPI 3.0 using annotation @io.swagger.v3.oas.annotations.security.SecurityScheme
in a @Configuration
bean:
@Configuration
@OpenAPIDefinition(info = @Info(title = "My API", version = "v1"))
@SecurityScheme(
name = "bearerAuth",
type = SecuritySchemeType.HTTP,
bearerFormat = "JWT",
scheme = "bearer"
)
public class OpenApi30Config {
}
Annotate each @RestController
method requiring Bearer Token Authentication (JWT) with @io.swagger.v3.oas.annotations.Operation
referencing the defined security scheme:
@Operation(summary = "My endpoint", security = @SecurityRequirement(name = "bearerAuth"))
If you want to avoid annotating each and every @Operation
inside your @RestController
with the security
attribute, you can add this at class level affecting every operation of your controller.
Please don't forget that your configuration bean needs to be the same as in the other example:
@Configuration
@OpenAPIDefinition(info = @Info(title = "My API", version = "v1"))
@SecurityScheme(
name = "bearerAuth",
type = SecuritySchemeType.HTTP,
bearerFormat = "JWT",
scheme = "bearer"
)
public class OpenApi30Config {
}
All you have to do is just use @SecurityRequirement(name = "bearerAuth")
on those classes, where you would like to restrict the API calls. Note, that these annotations are inherited, so you can add them to any interface as well.
Create a marker interface with the required annotation:
@SecurityRequirement(name = "bearerAuth")
public interface SecuredRestController {
}
Add the marker interface to those controllers where you would like to apply the restriction to all operations, for example:
@RestController
@RequestMapping("/hello")
public class HelloController implements SecuredController {
@GetMapping
public String hello() {
return "Hello World";
}
@GetMapping("/{name}")
public String helloWithName(@PathVariable String name) {
return "Hello " + name;
}
}
You can do this without the marker interface just saying:
@RestController
@RequestMapping("/hello")
@SecurityRequirement(name = "bearerAuth")
public class HelloController {
...
}
Now you have both operations protected and requiring a JWT token.
As it was said in another post, you have to add the @SecurityRequirement
to your @Operation
annotation of your method.
@RestController
@RequestMapping("/hello")
public class HelloController {
@GetMapping
@Operation(summary = "My endpoint", security = @SecurityRequirement(name = "bearerAuth"))
public String hello() {
return "Hello World";
}
@GetMapping("/{name}")
public String helloWithName(@PathVariable String name) {
return "Hello " + name;
}
}
This restricts only the first operation, but not the second.
I have found a cleaner solution. It works fine for me.
Thanks to @JenkaBY.
package com.aliyun.horoscope.verse.configuration;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springdoc.core.customizers.OpenApiCustomiser;
import org.springframework.stereotype.Component;
@Component
public class AuthOpenApiCustomizer implements OpenApiCustomiser {
@Override
public void customise(OpenAPI openApi) {
var securitySchemeName = "bearerAuth";
openApi.getComponents().addSecuritySchemes(securitySchemeName, new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT"));
openApi.addSecurityItem(new SecurityRequirement().addList(securitySchemeName));
}
}