3

I'm developing a webflux app containing some public and protected resources.

My dependencies:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>3.0.0</version>
            <type>pom</type>
            <scope>import</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-stater-web</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springdoc</groupId>
        <artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
        <version>2.0.0</version>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-api</artifactId>
        <version>0.11.5</version>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-impl</artifactId>
        <version>0.11.5</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-jackson</artifactId>
        <version>0.11.5</version>
        <scope>runtime</scope>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.liquibase.ext</groupId>
        <artifactId>liquibase-mongodb</artifactId>
        <version>4.20.0</version>
    </dependency>
    <dependency>
        <groupId>org.liquibase</groupId>
        <artifactId>liquibase-core</artifactId>
        <version>4.20.0</version>
    </dependency>
</dependencies>

application.yml:

spring:
  main:
    web-application-type: reactive
  data:
    mongodb:
      port: 27017
      database: vilya_be
  liquibase:
    change-log: classpath:/mongo/changelog-master.xml

springdoc:
  api-docs:
    path: /v3/swagger-ui.html
  swagger-ui:
    path: /v3/api-docs

Java code:

@Configuration
@EnableWebFluxSecurity
@EnableMethodSecurity(securedEnabled = true, jsr250Enabled = true)
@RequiredArgsConstructor
public class JWTSecurityConfig {

  private final BearerAuthenticationFilter bearerAuthenticationFilter;

  @Bean
  public SecurityWebFilterChain filterChain(ServerHttpSecurity http) {
    return http.cors()
        .and()
        .csrf()
        .disable()
        .httpBasic()
        .disable()
        .exceptionHandling()
        .authenticationEntryPoint(entryPoint)
        .and()
        .authorizeExchange()
        .pathMatchers(USER_V1 + REGISTRATION, USER_V1 + SIGN_IN, "/v3/**")
        .permitAll()
        .anyExchange()
        .authenticated()
        .and()
        .securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
        .addFilterAt(
            bearerAuthenticationFilter,
            SecurityWebFiltersOrder.AUTHENTICATION)
        .build();
  }
}

@RestController
@RequestMapping(USER_V1)
@RequiredArgsConstructor
public class UserResource {

  private final UserService userService;
  private final AuthenticationService authenticationService;

  @PostMapping(REGISTRATION)
  public Mono<RegistrationResponse> register(
      @Valid @RequestBody Mono<RegistrationRequest> request) {
    return userService.register(request);
  }

  @PostMapping(SIGN_IN)
  public Mono<TokenPayload> signIn(@RequestBody Mono<SignInRequest> request) {
    return authenticationService.authenticate(request);
  }

  @GetMapping
  public Flux<User> findAll() {
    return userService.findAll();
  }
}

The first two apis are public and I have no issue with them, but the last api is protected, so I expect the swagger ui will have an Authorize or Header section to let me put the bearer token. Current behavior: See it

As I mentioned, I'm using springdoc-openapi-starter-webflux-ui and I think it will have auto-configuration so I guess that I don't need to create a @Bean of type OpenAPI manually. But I don't know how to config it to respect my security config. Please help, I'm also new to swagger.

PS: There is no smart lock icon, it just a copy icon. Btw, no Authorization button. enter image description here

SoT
  • 898
  • 1
  • 15
  • 36

1 Answers1

2

According to the docs:

You should add the @SecurityRequirement tags to your protected APIs.

For example:

@Operation(security = { @SecurityRequirement(name = "bearer-key") })

And the security definition sample:

  @Bean
  public OpenAPI customOpenAPI() {
    return new OpenAPI()
        .components(
            new Components()
                .addSecuritySchemes(
                    "bearer-key",
                    new SecurityScheme()
                        .type(SecurityScheme.Type.HTTP)
                        .scheme("bearer")
                        .bearerFormat("JWT")));
  }

After that, a small lock icon will appear on the right side of the protected APIs and if clicked the authorization popup will show up.

sc

authorize_popup

There will also be the authorize button in the top right corner of the swagger-ui page which does the same.

authorize_button

Toni
  • 3,296
  • 2
  • 13
  • 34