Подтвердить что ты не робот

Как настроить фильтр Access-Control-Allow-Origin проблематично в Spring Security 3.2

Я пытаюсь настроить мой Spring сервер с помощью Spring Security 3.2, чтобы выполнить запрос на вход в ajax.

Я следил за видео Spring Security 3.2 и несколькими сообщениями, но проблема в том, что я получаю

 No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:9000' is therefore not allowed access. 

Для запросов на вход в систему (см. ниже).

Я создал настройку CORSFilter, и я могу получить доступ к незащищенным ресурсам в моей системе с добавлением соответствующих заголовков в ответ.

Я предполагаю, что я не добавляю цепочку фильтров CORSFilter в цепочку фильтров безопасности, или может быть слишком поздно в цепочке. Любая идея будет оценена по достоинству.

WebAppInitializer

public class WebAppInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) {
        WebApplicationContext rootContext = createRootContext(servletContext);

        configureSpringMvc(servletContext, rootContext);

        FilterRegistration.Dynamic corsFilter = servletContext.addFilter("corsFilter", CORSFilter.class);
        corsFilter.addMappingForUrlPatterns(null, false, "/*");
    }

    private WebApplicationContext createRootContext(ServletContext servletContext) {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();

        rootContext.register(SecurityConfig.class, PersistenceConfig.class, CoreConfig.class);

        servletContext.addListener(new ContextLoaderListener(rootContext));
        servletContext.setInitParameter("defaultHtmlEscape", "true");

        return rootContext;
    }


    private void configureSpringMvc(ServletContext servletContext, WebApplicationContext rootContext) {
        AnnotationConfigWebApplicationContext mvcContext = new AnnotationConfigWebApplicationContext();
        mvcContext.register(MVCConfig.class);

        mvcContext.setParent(rootContext);
        ServletRegistration.Dynamic appServlet = servletContext.addServlet(
                "webservice", new DispatcherServlet(mvcContext));
        appServlet.setLoadOnStartup(1);
        Set<String> mappingConflicts = appServlet.addMapping("/api/*");

        if (!mappingConflicts.isEmpty()) {
            for (String s : mappingConflicts) {
                LOG.error("Mapping conflict: " + s);
            }
            throw new IllegalStateException(
                    "'webservice' cannot be mapped to '/'");
        }
    }

SecurityWebAppInitializer:

public class SecurityWebAppInitializer extends AbstractSecurityWebApplicationInitializer {
}

SecurityConfig:

Запросы/api/users - работают хорошо, а заголовки Access-Control-Allow добавлены. Я отключил csrf и заголовки, чтобы убедиться, что это не так.

@EnableWebMvcSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
    protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user").password("password").roles("USER");
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .headers().disable()                
            .authorizeRequests()
                    .antMatchers("/api/users/**").permitAll()
                    .anyRequest().authenticated()
                    .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }

CORFilter:

@Component
public class CORSFilter implements Filter{
    static Logger logger = LoggerFactory.getLogger(CORSFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
        chain.doFilter(request, response);
    }

    public void destroy() {}
}

Запрос на вход:

Request URL:http://localhost:8080/devstage-1.0/login
Request Headers CAUTION: Provisional headers are shown.
Accept:application/json, text/plain, */*
Cache-Control:no-cache
Content-Type:application/x-www-form-urlencoded
Origin:http://127.0.0.1:9000
Pragma:no-cache
Referer:http://127.0.0.1:9000/
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36
Form Dataview sourceview URL encoded
username:user
password:password
4b9b3361

Ответ 1

Все, что мне не хватало, было AddFilterBefore при настройке конфигурации безопасности.

Итак, окончательная версия:

@EnableWebMvcSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication()
        .withUser("user").password("password").roles("USER");
  }


  @Override
  protected void configure(HttpSecurity http) throws Exception {
      http
          .addFilterBefore(new CORSFilter(), ChannelProcessingFilter.class)

          .formLogin()
              .loginPage("/login")
              .and()
          .authorizeRequests()
              .anyRequest().authenticated();

И удалите CORSFilter из WebAppInitializer

Ответ 2

Я знаю, что это слишком поздно, чтобы ответить на ваш вопрос, но мысль может стоить поделиться. В вашей первоначальной конфигурации вы зарегистрировали метаданные конфигурации инициализатора безопасности Spring с корневым контекстом:

rootContext.register(SecurityConfig.class, PersistenceConfig.class, CoreConfig.class);

Если вы можете это сделать, вам не нужно, поскольку он свяжет цепочку фильтров безопасности с контекстом веб-приложения, который не требуется. Вместо этого вы можете просто добавить цепочку фильтров простым способом, зарегистрировав DelegatingFilterProxy в качестве фильтра. Конечно, вам нужно сохранить заказ, добавив фильтр Cors, прежде чем добавлять цепочку фильтров безопасности Spring.

Таким образом, вы сможете использовать запас CorsFilter (просто добавив параметры init), который поставляется вместе с пакетом org.apache.catalina.filters. В любом случае, вы можете придерживаться своей собственной конфигурации тоже!:)