Search code examples
javaspring-bootspring-securityjava-8

Can spring security specify different UserDetailsService instances for different paths?


The following code is wrong, but I hope that one day it will be supported.

Of course, I must first thank the developers of spring security and related components. Thank you for allowing us to write safe software so easily.

@Configuration
class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier("AdminerDetailsService")
    UserDetailsService adminerDetailsService;

    @Autowired
    @Qualifier("UserDetailsService")
    UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeRequests()
                .antMatchers("/backend-admin/**").hasRole("REGULAR")
                .userDetailsService(adminerDetailsService)
                .loginProcessingUrl("/login/admin")
                .authorizeRequests()
                .antMatchers("/backend-ContentCentre/**").hasRole("NORMAL")
                .userDetailsService(userDetailsService)
                .loginProcessingUrl("/login/user")
                .anyRequest().permitAll();
    }
}

The above code basically shows my intention. Users accessing /backend-ContentCentre use different UserDetailService implementation from that for accessing /backend-admin. How should I configure to achieve this target?

Thanks a lot.


Solution

  • You can have them into separate configurations. Still, they must be annotated with @Order :

    @Configuration
    @EnableWebSecurity
    public class SimpleSecurityConfiguration {
    
        @Order(1)
        @Configuration
        public static class AdminConfiguration extends WebSecurityConfigurerAdapter {
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http
                    .antMatcher("/backend-admin/**")
                    .authorizeRequests(authz -> authz.anyRequest().permitAll())
                    .login(login -> login
                        .loginUrl("/login/admin")
                    );
            }
    
            @Override
            protected void configure(AuthenticationManagerBuilder auth) {
                auth.userDetailsService(adminDetailsService);
            }
        }
    
    
        @Order(2)
        @Configuration
        public static class AdminConfiguration extends WebSecurityConfigurerAdapter {
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http
                    .antMatcher("/backend-user/**")
                    .authorizeRequests(authz -> authz.anyRequest().permitAll())
                    .login(login -> login
                        .loginUrl("/login/user")
                    );
            }
    
            @Override
            protected void configure(AuthenticationManagerBuilder auth) {
                auth.userDetailsService(userDetailsService);
            }
        }
    }
    

    Note the use of lambda for constructing the login and the authorizations. Also, the code provided in the question doesn't permit to distinguish which userService to use for each path