SpringBoot multiple authentication adapter

天大地大妈咪最大 提交于 2019-11-30 20:23:13

I experienced some headaches when implementing basic authentication next to Keycloak authentication, because still while doing multiple WebSecurityAdapter implementations 'by the book', the Keycloak authentication filter was called even when basic authentication succeeded.

The reason lies here: http://www.keycloak.org/docs/latest/securing_apps/index.html#avoid-double-filter-bean-registration

So if you use the Keycloak Spring Security Adapter together with Spring Boot, make sure to add those two beans (in addition to the valid answer by Jacob von Lingen):

@Configuration
@EnableWebSecurity
public class MultiHttpSecurityConfig {

    @Configuration
    @Order(1) //Order is 1 -> First the special case
    public static class DownloadableExportFilesSecurityConfig extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception 
        {
            http
                .antMatcher("/download/export/test")
                    .authorizeRequests()
                    .anyRequest().hasRole("USER1")
                .and()
                    .httpBasic();
        }

        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
              .withUser("user").password("password1").roles("USER1");
        }

    }

    @Configuration
    @ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
    //no Order, will be configured last => All other urls should go through the keycloak adapter
    public static class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

       auth.authenticationProvider(keycloakAuthenticationProvider());
        }

        @Bean
        @Override
        protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
            return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
        }

        // necessary due to http://www.keycloak.org/docs/latest/securing_apps/index.html#avoid-double-filter-bean-registration
        @Bean
        public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean(KeycloakAuthenticationProcessingFilter filter) {
            FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
            registrationBean.setEnabled(false);
            return registrationBean;
        }
        // necessary due to http://www.keycloak.org/docs/latest/securing_apps/index.html#avoid-double-filter-bean-registration
        @Bean
        public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean(KeycloakPreAuthActionsFilter filter) {
            FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
            registrationBean.setEnabled(false);
            return registrationBean;
        }


        @Override
        protected void configure(HttpSecurity http) throws Exception 
        {
            super.configure(http);
            http
                .authorizeRequests()
                .anyRequest().hasAnyRole("ADMIN", "SUPER_ADMIN")
                .and()
                .logout().logoutSuccessUrl("/bye");
        }

    }
}

The key for multiple HttpSecurity is to register the 'special cases' before the normal one. In other words, the /download/export/test authentication adapter should be registered before the keycloak adapter.

Another important thing to notice, once an authentication is successful, no other adapter is called (so the .regexMatcher("^(?!.*/download/export/test)") is not necessary). More info for Multiple HttpSecurity can be found here.

Below you code with minimal changes:

@Configuration
@EnableWebSecurity
public class MultiHttpSecurityConfig {

    @Configuration
    @Order(1) //Order is 1 -> First the special case
    public static class DownloadableExportFilesSecurityConfig extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .antMatcher("/download/export/test")
                    .authorizeRequests()
                    .anyRequest().hasRole("USER1")
                .and()
                    .httpBasic();
        }

        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                .withUser("user").password("password1").roles("USER1");
        }

    }

    @Configuration
    @ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
    @Order(2) //Order is 2 -> All other urls should go through the keycloak adapter
    public static class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
            auth.authenticationProvider(keycloakAuthenticationProvider());
        }

        @Bean
        @Override
        protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
            return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            super.configure(http);
            http
                //removed .regexMatcher("^(?!.*/download/export/test)")
                .authorizeRequests()
                    .anyRequest().hasAnyRole("ADMIN", "SUPER_ADMIN")
                .and()
                    .logout().logoutSuccessUrl("/bye");
        }

    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!