使用同一API的Spring Security Basic Auth和Form登录

时间:2018-08-13 12:59:43

标签: spring spring-mvc spring-boot spring-security spring-security-oauth2

我想通过两种身份验证机制(基本身份验证和表单登录)访问我所有的API。我知道这里存在问题,但是答案对我没有用,我的用例有些不同。

我的配置:

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {

    @Configuration
    @Order(1)
    public static class SecurityConfigBasicAuth extends WebSecurityConfigurerAdapter {

        final private RestAuthenticationEntryPoint restAuthenticationEntryPoint;

        @Autowired
        public SecurityConfigBasicAuth(RestAuthenticationEntryPoint restAuthenticationEntryPoint,
                                       @Qualifier("customUserDetailsService") UserDetailsService userDetailsService) {
            this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
            this.userDetailsService = userDetailsService;
        }

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(userDetailsService);
            auth.authenticationProvider(authenticationProvider());
        }

        // @Bean authenticationProvider()

        // @Bean passwordEncoder()

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests().anyRequest().authenticated()
                    .and()
                    .cors()
                    .and()
                    .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .csrf().disable()
                    .httpBasic()
                    .authenticationEntryPoint(restAuthenticationEntryPoint)
                    .and()
                    .formLogin().disable()
                    .logout().disable();
        }
    }

    @Configuration
    public static class SecurityConfigFormLogin extends WebSecurityConfigurerAdapter {

        final private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
        final private RestfulSavedRequestAwareAuthenticationSuccessHandler restfulSavedRequestAwareAuthenticationSuccessHandler;
        final private CustomAuthenticationProvider customAuthenticationProvider;

        @Autowired
        public SecurityConfigFormLogin(RestAuthenticationEntryPoint restAuthenticationEntryPoint,
                                       RestfulSavedRequestAwareAuthenticationSuccessHandler restfulSavedRequestAwareAuthenticationSuccessHandler,
                                       CustomAuthenticationProvider hashAuthenticationProvider) {
            this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
            this.restfulSavedRequestAwareAuthenticationSuccessHandler = restfulSavedRequestAwareAuthenticationSuccessHandler;
            this.customAuthenticationProvider = customAuthenticationProvider;
        }

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.authenticationProvider(customAuthenticationProvider);
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests().anyRequest().authenticated()
                    .and()
                    .cors()
                    .and()
                    .csrf().disable()
                    .exceptionHandling()
                    .authenticationEntryPoint(restAuthenticationEntryPoint)
                    .and()
                    .csrf().disable()
                    .httpBasic().disable()
                    .formLogin()
                    .usernameParameter("id1")
                    .passwordParameter("Id2")
                    .loginProcessingUrl("/test/login")
                    .successHandler(restfulSavedRequestAwareAuthenticationSuccessHandler)
                    .failureHandler(myFailureHandler())
                    .and()
                    .logout();
        }

        // @Bean myFailureHandler()
    }
}

如您所见,我定义了两个“ WebSecurityConfigurerAdapters”,一个用于基本身份验证,一个用于表单登录。表单登录与REST兼容(不重定向,但提供HTTP响应)。

问题如下:加载的第一个“ WebSecurityConfigurerAdapter”可以工作,并且覆盖第二个。上面的示例使使用基本身份验证成为可能,但是我无法登录POST'/ test / login',却得到了:

{
    "timestamp": 1534164906450,
    "status": 401,
    "error": "Unauthorized",
    "message": "Unauthorized",
    "path": "/test/login"
}

已修复更新:关键是使用“ requestMatchers()”,请参见答案部分以获取解决方案(由jzheaux建议)

1 个答案:

答案 0 :(得分:2)

好的,这就是我的解决方法:

我将基本身份验证配置配置为:

protected void configure(HttpSecurity http) throws Exception {
    http.requestMatchers()
            .antMatchers("/api/**")
            .and()
            .cors()
            .and()
            .csrf().disable()
            .httpBasic()
            .authenticationEntryPoint(restAuthenticationEntryPoint)
            .and();
}

如果您不希望基本身份验证返回带有新JSESSIONID的新cookie,请添加:

            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.NEVER)
            .sessionFixation()
            .migrateSession()

表单登录配置为:

 protected void configure(HttpSecurity http) throws Exception {
            http.requestMatchers()
                    .antMatchers(HttpMethod.POST, "/test/login")
                    .and()
                    .cors()
                    .and()
                    .csrf().disable()
                    .exceptionHandling()
                    .authenticationEntryPoint(restAuthenticationEntryPoint)
                    .and()
                    .formLogin()
                    .usernameParameter("id1")
                    .passwordParameter("id2")
                    .loginProcessingUrl("/test/login")
                    .successHandler(authenticationSuccessHandler)
                    .failureHandler(myFailureHandler())
                    .and()
                    .logout();
        }

现在,我可以通过Form登录配置进行身份验证,并使用cookie会话ID调用/ api / **(在“基本身份验证”配置中配置)。我也可以只使用课程的基本身份验证。