Как проблемно настроить фильтр 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
2 ответа
Все, чего мне не хватало, это 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
Я знаю, что уже слишком поздно, чтобы ответить на ваш вопрос, но, возможно, стоит поделиться. В вашей начальной конфигурации вы зарегистрировали метаданные конфигурации инициализатора Spring Security с корневым контекстом:
rootContext.register(SecurityConfig.class, PersistenceConfig.class, CoreConfig.class);
Когда вы можете сделать это, вам это не нужно, поскольку это соединит цепочку фильтров безопасности с контекстом веб-приложения, который не требуется. Вместо этого вы можете просто добавить цепочку фильтров простым старым способом, зарегистрировав DelegatingFilterProxy в качестве фильтра. Конечно, вам нужно будет поддерживать порядок, добавив фильтр Cors, прежде чем добавлять цепочку фильтров безопасности Spring.
Таким образом, вы сможете использовать стандартный CorsFilter (просто добавив init-параметры), который поставляется с пакетом org.apache.catalina.filters. В любом случае, вы можете придерживаться своей собственной конфигурации тоже!:)