Spring Boot CORS Filter不支持AngularJS

时间:2017-09-28 05:18:09

标签: java angularjs spring-boot cors activiti

我创建了一个SpringBoot应用程序,它有一个AngularJS前端,我没有使用任何Spring Security模块。

我在控制器中添加了@CrossOrigin注释,如下所示

@CrossOrigin(origins = "http://localhost:3000", maxAge = 3600)
@RestController
public class MyController {
   public static final Logger logger = LoggerFactory.getLogger(MyController.class);
   .....
   .....

我还创建了一个CORS过滤器,如下所示。

@Component
public class CORSFilter implements Filter {

public void doFilter(ServletRequest req, 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, PUT, OPTIONS, DELETE");
    response.setHeader("Access-Control-Max-Age", "3600");
    response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    chain.doFilter(req, res);
}

public void init(FilterConfig filterConfig) {}
public void destroy() {}

}

我在angularJS前端的OPTIONS中收到以下错误

XMLHttpRequest cannot load http://localhost:8080/abc/books/. Response for preflight has invalid HTTP status code 401 (edited)

[12:10] 
zone.js:2744 OPTIONS http://localhost:8080/abc/books/ 401 ()

我的SpringBoot应用程序适用于PostMan,当我使用Chrome时会发生此预检错误。我该如何解决?

修改

我还使用了有以下内容的activiti-spring-boot-starter-rest-api:

import org.activiti.engine.IdentityService;
import org.activiti.engine.identity.User;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class AuthenticationService {

@Bean
InitializingBean usersAndGroupsInitializer(final IdentityService identityService) {

    return new InitializingBean() {
        public void afterPropertiesSet() throws Exception {
            User admin = identityService.newUser("admin");
            admin.setPassword("admin");
            identityService.saveUser(admin);
            }
        };
    }

}

2 个答案:

答案 0 :(得分:2)

正如评论中所提到的,问题是activiti-spring-boot-starter-rest-api带有开箱即用的安全性。这里的问题是它们在根上下文上应用安全性,这意味着任何其他端点也将具有身份验证。

选项1:添加自己的安全性

要解决此问题,您可以创建具有更高优先级的自己的SecurityConfig类,并允许所有请求转到/abc/**(或其他任何内容),例如:

@Order(Ordered.HIGHEST_PRECEDENCE) // This should "overrule" Activiti's security
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/abc/**")
            .authorizeRequests().anyRequest().permitAll();
    }
}

选项2:禁用Activiti的安全性

或者,您可以禁用Activiti的安全自动配置:

@EnableAutoConfiguration(exclude = {
    org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration.class,
    org.activiti.spring.boot.SecurityAutoConfiguration.class
})

这将禁用Activiti和Spring启动本身的安全自动配置。如果你只是禁用Activiti的安全配置,Spring boot的自动配置就会启动,你仍然可以在所有端点上进行身份验证。

但是,您可能仍希望在某些Activiti的端点上应用安全性,但这允许您自己进行自定义,而不是依赖于自动配置。在您的情况下,您可以选择对所有/identity/**/management/**/history/**/repository/**/query/**/runtime/**路径应用安全性,正在被Activiti使用。

选项3:在OPTIONS

的情况下覆盖过滤器链

第三种选择是绕过整个安全过滤链。如this answer所示,您可以通过不调用chain.doFilter(req, res)来突破过滤器链。这可以通过在过滤器中添加以下内容来完成:

if (HttpMethod.OPTIONS.name().equalsIgnoreCase(req.getMethod()) {
    res.setStatus(HttpServletResponse.SC_OK);
} else {
    chain.doFilter(req, res); // Only apply doFilter() when not OPTIONS
}
  

注意:请注意,这只会允许OPTIONS来电。安全性还会影响您在控制器中定义的其他端点,而不仅仅是OPTIONS调用。

通过有条件地调用doFilter(),您可以跳过整个安全过滤器链,以防OPTIONS请求进入。您必须将reqres投射到{{分别为1}}和HttpServletRequest

此外,您必须确保此过滤器在安全过滤器链之前被称为。为此,请将HttpServletResponse的顺序更改为所选值,例如:

CORSFilter

现在通过将@Component @Order(1) // You can choose the value yourself public class CORSFilter implements Filter { // ... } 中的security.filter-order属性设置为更高的值来更改安全过滤器链顺序:

application.properties

答案 1 :(得分:1)

这是一个Spring CORS过滤器,可以与AngularJS一起使用

public class CORSFilter extends OncePerRequestFilter {

    private final Logger LOG = LoggerFactory.getLogger(CORSFilter.class);

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws ServletException, IOException {
        LOG.info("Adding CORS Headers ........................");        
        res.setHeader("Access-Control-Allow-Origin", "*");
        res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        res.setHeader("Access-Control-Max-Age", "3600");
        res.setHeader("Access-Control-Allow-Headers", "X-PINGOTHER,Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization");
        res.addHeader("Access-Control-Expose-Headers", "xsrf-token");
        if ("OPTIONS".equals(req.getMethod())) {
            res.setStatus(HttpServletResponse.SC_OK);
        } else { 
            chain.doFilter(req, res);
        }        
    }

我是从帖子Spring cors allow all origins

中找到的