I added this dependency to my Spring Boot application
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.4.3</version>
<type>pom.sha512</type>
</dependency>
I then was able to open : https://localhost:8443/v3/api-docs
The browser does ask me for my credentials, and as long as I enter the user/password right it works, but it shows me ALL the methods that are available globally. I would like only the methods the user has rights to, to show up in the api docs.
For a specific method is use this tag to authorize my call:
@PreAuthorize("hasRole('USER') OR hasRole('ADMIN')")
This is my web security config class:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.inMemoryAuthentication()
.passwordEncoder(new BCryptPasswordEncoder())
.withUser("user").password(new BCryptPasswordEncoder().encode("blabl")).roles("USER")
.and()
.withUser("admin").password(new BCryptPasswordEncoder().encode("blabla")).roles("ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception
{
http.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic();
}
}
Basically, the way to do this is to utilize OperationCustomizer
which you can then create conditional logic that excludes endpoints from the docs based on role:
import org.springdoc.core.customizers.OperationCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.method.HandlerMethod;
import io.swagger.v3.oas.models.Operation;
@Configuration
public class OpenApiConfig
{
@Bean
public OperationCustomizer operationCustomizer()
{
return (Operation operation, HandlerMethod handlerMethod) ->
{
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.isAuthenticated())
{
PreAuthorize preAuthorize = handlerMethod.getMethodAnnotation(PreAuthorize.class);
if (preAuthorize != null)
{
String[] requiredRoles = preAuthorize.value().replace("hasRole('", "").replace("')", "").split(" OR ");
boolean hasRole = false;
for (GrantedAuthority authority : authentication.getAuthorities())
{
for (String role : requiredRoles)
{
if (authority.getAuthority().equals("ROLE_" + role))
{
hasRole = true;
break;
}
}
if (hasRole)
{
break;
}
}
if (!hasRole)
{
return null; // Exclude the operation if the user does not have any of the required roles
}
}
} else
{
System.out.println("No authenticated user found.");
return null;
}
return operation;
};
}
}