I need my /api/**
endpoints to be accessible using either a JWT token or a login/password.
I took inspiration from Spring documentation: https://docs.spring.io/spring-security/reference/servlet/configuration/java.html#_multiple_httpsecurity
But I may have misunderstood the example, and my API endpoints are only accessible using basic authent with this configuration :
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration {
static final int BCRYPT_PASSWORD_STRENGTH = 10;
@Bean
@Order(1)
public SecurityFilterChain apiSecurityFilterChain(HttpSecurity http, @Qualifier("apiUserDetailsService") UserDetailsService userDetailsService) throws Exception {
http.antMatcher("/api/**")
.userDetailsService(userDetailsService)
.csrf().disable()
.cors(Customizer.withDefaults())
.exceptionHandling(configurer -> configurer.authenticationEntryPoint(new AuthenticationFallbackEntryPoint()))
.sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
.httpBasic(Customizer.withDefaults());
return http.build();
}
@Bean
@Order(2)
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http, GrantedPortalRoleConverter grantedPortalRoleConverter) throws Exception {
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedPortalRoleConverter);
http
.csrf().disable()
.cors(Customizer.withDefaults())
.exceptionHandling(configurer -> configurer.authenticationEntryPoint(new AuthenticationFallbackEntryPoint()))
.sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authorize -> authorize
.antMatchers(
"/swagger-ui/**",
"/swagger-ui.html",
"/swagger-resources/**",
"/v3/api-docs/**")
.permitAll()
.anyRequest().authenticated())
.oauth2ResourceServer(configurer -> configurer.jwt().jwtAuthenticationConverter(jwtAuthenticationConverter));
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(BCRYPT_PASSWORD_STRENGTH);
}
}
How should I tweak this conf (still using SecurityFilterChain
) to achieve my goal?
CodePudding user response:
Here it is, the working config :
@Bean
@Order(1)
public SecurityFilterChain basicAuthSecurityFilterChain(HttpSecurity http, @Qualifier("apiUserDetailsService") UserDetailsService userDetailsService) throws Exception {
http.requestMatcher(new BasicAuthRequestMatcher())
.userDetailsService(userDetailsService)
.csrf().disable()
.cors(Customizer.withDefaults())
.exceptionHandling(configurer -> configurer.authenticationEntryPoint(new AuthenticationFallbackEntryPoint()))
.sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
.httpBasic(Customizer.withDefaults());
return http.build();
}
@Bean
@Order(2)
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http, GrantedPortalRoleConverter grantedPortalRoleConverter) throws Exception {
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedPortalRoleConverter);
http
.csrf().disable()
.cors(Customizer.withDefaults())
.exceptionHandling(configurer -> configurer.authenticationEntryPoint(new AuthenticationFallbackEntryPoint()))
.sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authorize -> authorize
.antMatchers(
"/swagger-ui/**",
"/swagger-ui.html",
"/swagger-resources/**",
"/v3/api-docs/**")
.permitAll()
.anyRequest().authenticated())
.oauth2ResourceServer(configurer -> configurer.jwt().jwtAuthenticationConverter(jwtAuthenticationConverter));
return http.build();
}
And the RequestMatcher :
public class BasicAuthRequestMatcher implements RequestMatcher {
@Override
public boolean matches(HttpServletRequest request) {
boolean matches = false;
String authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
if (authorizationHeader != null && authorizationHeader.startsWith("Basic")) {
matches = true;
}
return matches;
}
}