I have a spring boot application that provides mainly REST endpoints, authentication is done via token (sent in Authorization
header) where I have my own TokenAuthenticationFilter
added before LogoutFilter
to set the security context.
In the process of creating an admin console, I want admin authentication to be separate from regular users, as I'm not sharing tables between Admins
and Users
for several reasons, on the database level I have the following user,user_token,admin,admin_token
. So in order to accomplish this, I thought of several solutions:
TokenAuthenticationFilter
handle user/admin token
auth. This however will require to either: Modify the filter to
determine whether it's an admin or a user token based on url pattern
(so for example if it's /admin/**
, the filter will know which
service to call) or have the admins header unique from the users
(i.e. User sends U-Auth header, Admin sends A-Auth header) and the filter will act based on header name. This all
doesn't sound good to me./admin/**
will have AdminTokenAuthFilter
added to the chain,
while any other pattern will have the old
TokenAuthenticationFilter
in the chain. This sounds better than
the earlier approach but I'm having trouble to implement it. I tried
to register my own FilterRegistrationBean
inside my WebSecurityConfigurerAdapter
Example:
@Bean
public FilterRegistrationBean adminFilter(){
FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
filterRegBean.setFilter(new AdminTokenAuthFilter());
List<String> urlPatterns = new ArrayList<>();
urlPatterns.add("/admin/*");
filterRegBean.setUrlPatterns(urlPatterns);
return filterRegBean;
}
This seems to work but I'm unsure if it's proper practice also I'm concerned about one thing, I found that this adds the filter to the springs originalChain
of filters, not to the additionalFilters
that seems to apply when adding filters regularly in my WebSecurityConfigurerAdapter
using http.addFilterBefore(tokenAuthenticationFilter, LogoutFilter.class)
. I don't want to alter springs original filter chain, i'd rather have my custom filters in the additional filter chain. Can anyone elaborate on this please?
dispatcherServlet
will have its own security configuration.Can anybody share some knowledge on what's the best approach in such a scenario?
Ended up writing two security configurations, the first one applies to a specific antmatcher, the second one is for any other url pattern. Like so:
@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = "x.x.x")
public class NewSecurityConfiguration {
@Configuration
@Order(1)
public static class BackendSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired CustomSystemUserDetailsService customSystemUserDetailsService;
@Autowired SystemTokenAuthFilter systemTokenAuthFilter;
@Autowired CustomLogoutFilter customLogoutFilter;
@Autowired UnauthorizedEntryPoint unauthorizedEntryPoint;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean(name="systemAuthenticationManager")
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customSystemUserDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/system/**")
.addFilterBefore(systemTokenAuthFilter, LogoutFilter.class)
.addFilterBefore(customLogoutFilter, LogoutFilter.class)
.authorizeRequests()
.antMatchers("/system/login").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling().authenticationEntryPoint(unauthorizedEntryPoint)
.and()
.httpBasic().disable()
.csrf().disable()
.logout().disable();
}
}
@Configuration
@Order(2)
public static class FrontEndSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(userTokenAuthFilter, LogoutFilter.class)
.addFilterBefore(customLogoutFilter, LogoutFilter.class)
.authorizeRequests()
.antMatchers("/access/*").permitAll()
.antMatchers("/ref/*").permitAll()
.antMatchers("/ticket_parser/*").permitAll()
.antMatchers("/reset_password/**").permitAll()
.antMatchers("/link_profile/**").permitAll()
.antMatchers("/email_verification/**").permitAll()
.antMatchers("/ref").permitAll()
.antMatchers("/flightstats/alert").permitAll()
.antMatchers("/airline/list").access("authenticated or hasIpAddress('127.0.0.1') or hasIpAddress('0:0:0:0:0:0:0:1')")
.antMatchers("/airport/list").access("authenticated or hasIpAddress('127.0.0.1') or hasIpAddress('0:0:0:0:0:0:0:1')")
.and()
.authorizeRequests().anyRequest().authenticated().and().authorizeRequests()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling().authenticationEntryPoint(unauthorizedEntryPoint)
.and()
.httpBasic().disable()
.csrf().disable()
.formLogin().disable()
.logout().disable();
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With