Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
相同API的Spring security基本身份验证和表单登录_Spring_Spring Mvc_Spring Boot_Spring Security_Spring Security Oauth2 - Fatal编程技术网

相同API的Spring security基本身份验证和表单登录

相同API的Spring security基本身份验证和表单登录,spring,spring-mvc,spring-boot,spring-security,spring-security-oauth2,Spring,Spring Mvc,Spring Boot,Spring Security,Spring Security Oauth2,我想通过两种身份验证机制(基本身份验证和表单登录)访问我的所有API。我知道存在一些问题,但是,答案对我来说并不适用,我的用例有点不同 我的配置: @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig { @Configuration @Order(1) public static class SecurityConfigB

我想通过两种身份验证机制(基本身份验证和表单登录)访问我的所有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()
    }
}
如您所见,我定义了两个“WebSecurity配置适配器”,一个用于基本身份验证,另一个用于表单登录。表单登录与REST兼容(不重定向,但提供HTTP响应)

问题如下:加载的第一个“WebSecurityConfigureAdapter”工作并覆盖第二个。上面的示例使使用basic auth成为可能,但我无法登录POST'/test/login',我得到一个:

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

更新修复:关键是要使用“requestMatchers()”,请参见答案部分了解解决方案(如jzheaux所建议)

好的,我就是这样修复的:

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

protected void configure(HttpSecurity http) throws Exception {
    http.requestMatchers()
            .antMatchers("/api/**")
            .and()
            .cors()
            .and()
            .csrf().disable()
            .httpBasic()
            .authenticationEntryPoint(restAuthenticationEntryPoint)
            .and();
}
 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();
        }
如果不希望基本身份验证返回具有新JSESSIONID的新cookie,请添加:

            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.NEVER)
            .sessionFixation()
            .migrateSession()
表单登录配置为:

protected void configure(HttpSecurity http) throws Exception {
    http.requestMatchers()
            .antMatchers("/api/**")
            .and()
            .cors()
            .and()
            .csrf().disable()
            .httpBasic()
            .authenticationEntryPoint(restAuthenticationEntryPoint)
            .and();
}
 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();
        }

现在,我可以通过表单登录配置进行身份验证,并使用cookie会话id调用/api/**(在基本身份验证配置中配置)。当然,我也可以使用基本的身份验证。

在同一个端点上配置两组web安全过滤器不会有什么好处。我唯一能建议的是使用不同的URL,一个用于表单登录,一个用于基本身份验证-一旦经过身份验证,您就应该能够使用会话?其他的则不定义url路径。使用不同的url是什么意思?这两种身份验证都会产生特定的角色,在这些角色中,它们可以访问相同的API。这正是您所做的不同之处,也是它不起作用的原因。如果您确实需要两个不同的筛选器链,请先看http.requestMatchers()。这将允许您相当干净地按url拆分配置。您当前的配置可能存在的问题是,这些配置并没有完全覆盖它们,因为它们彼此合并(如果您不执行我上面建议的操作)。我很想亲自尝试一下,一个执行httpBasic,另一个执行httpBasic().disable的合并配置是什么。