Potrzebuję zaimplementować jednocześnie JWT i Basic auth. JWT obsługuje właściwie całą aplikację poza jednym endpointem (np /basicauth/*
), który jest obsługiwany przez Basic Auth.
Do JWT używam OncePerRequestFilter
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private Authenticator authenticatior;
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf()
.disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
.addFilterAfter(
new AuthenticationFilter(authenticatior),
UsernamePasswordAuthenticationFilter.class
)
.authorizeRequests()
.anyRequest()
.authenticated();
}
@Override
public void configure(WebSecurity web) {
web.ignoring()
.antMatchers(HttpMethod.GET, "/jwt")
.antMatchers(HttpMethod.OPTIONS, "/**")
.regexMatchers(
HttpMethod.POST,
"/jwt"
);
}
}
i działa perfect. Odłączam /jwt
od wymaganego tokenu, pozostałe endpointy wymagają nagłówka Authorization: Bearer
w żądaniu.
Niestety nie udaje mi się skonfigurować security tak, aby endpoitn /basicauth/*
był obsługiwany przez Basic Auth, nie przez JWT.
To co mam do teraz:
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private Authenticator authenticatior;
@Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("GUEST");
}
@Bean
public CustomBasicAuthenticationEntryPoint getBasicAuthEntryPoint(){
return new CustomBasicAuthenticationEntryPoint();
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/basicauth/**")
.hasRole("GUEST")
.and()
.httpBasic()
.realmName("BASICAUTHREALM")
.authenticationEntryPoint(getBasicAuthEntryPoint())
.and()
.antMatcher("/**")
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
.addFilterAfter(
new AuthenticationFilter(authenticatior),
UsernamePasswordAuthenticationFilter.class
)
.authorizeRequests()
.anyRequest()
.authenticated();
}
@Override
public void configure(WebSecurity web) {
web.ignoring()
.antMatchers(HttpMethod.GET, "/jwt")
.antMatchers(HttpMethod.OPTIONS, "/**")
.regexMatchers(
HttpMethod.POST,
"/jwt"
);
}
}
CustomBasicAuthenticationEntryPoint.java
:
public final class CustomBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
@Override
public void commence(final HttpServletRequest request,
final HttpServletResponse response,
final AuthenticationException authException) throws IOException {
//Authentication failed, send error response.
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.addHeader("WWW-Authenticate", "Basic realm=" + getRealmName() + "");
PrintWriter writer = response.getWriter();
writer.println("HTTP Status 401 : " + authException.getMessage());
}
@Override
public void afterPropertiesSet() {
setRealmName("MY_TEST_REALM");
super.afterPropertiesSet();
}
}
Taka konfiguracja zwraca 401 na każde żądanie /basicauth/*
i nie pyta o basic auth credentials.
Jak prawidłowo skonfigurować SecurityConfiguration
aby utrzymać jwt na istniejących endpointach i jednocześnie zabezpieczyć basicauth na /basicauth/*
?