HttpSecurity多个配置不会为配置的端点提供基本身份验证质询

时间:2017-06-16 13:05:04

标签: java spring spring-security

我已阅读Spring文档,并看到了多个HTTP配置的相关SO问题,但似乎我遗漏了一些东西。

当我尝试转到/api/endpoint/时遇到403错误,即使我希望收到基本的http身份验证质询。

@EnableWebSecurity
public class MultiHttpSecurityConfig {

    @Autowired
    private DataSource dataSource;

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

        auth
            .jdbcAuthentication()
                .dataSource(dataSource)
                .usersByUsernameQuery("select username,password, is_active from user where username=?")
                .authoritiesByUsernameQuery("select username, role from user_roles where username=?")
                .passwordEncoder(passwordEncoder());
    }

    @Configuration
    @Order(1)
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
        protected void configure(HttpSecurity http) throws Exception {
            http
                .antMatcher("/api/endpoint")
                .authorizeRequests()
                    .anyRequest().hasRole("ADMIN")
                    .and()
                .httpBasic();
        }
    }

    @Configuration
    public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                    .antMatchers("/").access("hasRole('ROLE_USER')")
                    .antMatchers("/customer/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')")
                    .antMatchers("/buy/**").access("hasRole('ROLE_ADMIN')")
                    .and()
                .formLogin()
                     .loginPage("/login")
                     .failureUrl("/login-error")
                     .usernameParameter("username")
                     .passwordParameter("password")
                     .and()
                .logout()
                     .logoutSuccessUrl("/login?logout")
                     .and()
                .exceptionHandling()
                     .accessDeniedPage("/error-403")
                      .and()
                .csrf();
        }
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
} 

应用程序初始化是:

@Override
public void onStartup(ServletContext container) {
    // Create the 'root' Spring application context
    AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
    rootContext.register(ServiceConfig.class, PersistenceConfiguration.class, MultiHttpSecurityConfig.class,
            MailConfig.class, MvcConfig.class);

    // Manage the lifecycle of the root application context
    container.addListener(new ContextLoaderListener(rootContext));
    container.addListener(new ApplicationCycleControlleristener());
    container.addFilter("springSecurityFilterChain", new DelegatingFilterProxy("springSecurityFilterChain"))
            .addMappingForUrlPatterns(null, false, "/*");

    // Create the dispatcher servlet's Spring application context
    AnnotationConfigWebApplicationContext dispatcherServlet = new AnnotationConfigWebApplicationContext();
    dispatcherServlet.register(MvcConfig.class);

    // Register and map the dispatcher servlet
    ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher",
            new DispatcherServlet(dispatcherServlet));
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/");

     MultipartConfigElement multipartConfigElement = new MultipartConfigElement(TMP_FOLDER, 
              MAX_UPLOAD_SIZE, MAX_UPLOAD_SIZE * 2, MAX_UPLOAD_SIZE / 2);

    dispatcher.setMultipartConfig(multipartConfigElement);
}

我希望文件说第一个会开始挑战,但似乎并非如此。

这是Spring调试显示的内容

[AntPathRequestMatcher.java:157] Checking match of request : '/api/endpoint'; against '/api/endpoint'
[FilterChainProxy.java:325] /api/endpoint at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
[FilterChainProxy.java:325] /api/endpoint at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
[HttpSessionSecurityContextRepository.java:174] No HttpSession currently exists
[HttpSessionSecurityContextRepository.java:116] No SecurityContext was available from the HttpSession: null. A new one will be created.
[FilterChainProxy.java:325] /api/endpoint at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
[HstsHeaderWriter.java:130] Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@33a327e2
[FilterChainProxy.java:325] /api/endpoint at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
[CsrfFilter.java:110] Invalid CSRF token found for http://localhost:8080/app/api/endpoint
[HttpSessionSecurityContextRepository.java:352] SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
[SecurityContextPersistenceFilter.java:119] SecurityContextHolder now cleared, as request processing completed
[DispatcherServlet.java:865] DispatcherServlet with name 'dispatcher' processing POST request for [/app/error-403]
[AbstractHandlerMethodMapping.java:310] Looking up handler method for path /error-403

1 个答案:

答案 0 :(得分:0)

以后参考具​​有相同问题的人。

似乎Spring Security默认启用了csrf,您需要在HttpSecurity configure方法中手动禁用它。我发现按预期工作的唯一方法如下:

@Configuration
@Order(1)
 public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
    protected void configure(HttpSecurity http) throws Exception {
// Build the request matcher for CSFR protection
        RequestMatcher csrfRequestMatcher = new RequestMatcher() {

            // Disable CSFR protection on the following urls:
            private AntPathRequestMatcher[] requestMatchers = { new AntPathRequestMatcher("/api/endpoint") };

            @Override
            public boolean matches(HttpServletRequest request) {

                if (request.getMethod().matches("^GET$"))
                    return false;
                for (AntPathRequestMatcher rm : requestMatchers) {
                    if (rm.matches(request)) {
                        return false;
                    }
                }
                return true;
            } // method matches
        };

        http.antMatcher("/api/endpoint").authorizeRequests().anyRequest().hasRole("ADMIN").and().httpBasic().and()
                .csrf().requireCsrfProtectionMatcher(csrfRequestMatcher);
    }
}

之后,一切似乎按照我的希望运作。在文档中也是好的。如果是,我没有注意到,请告诉我,并将更新答案。