Spring Boot CORS 过滤器不适用于 AngularJS
Posted
技术标签:
【中文标题】Spring Boot CORS 过滤器不适用于 AngularJS【英文标题】:Spring boot CORS Filter not working with AngularJS 【发布时间】:2018-03-09 17:52:26 【问题描述】:我创建了一个带有 AngularJS 前端的 SpringBoot 应用程序,但我没有使用任何 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);
;
【问题讨论】:
@g00glen00b 我没有启用弹簧安全 @g00glen00b 这是有道理的。我已经编辑了我的问题。我没有意识到 activiti 依赖可能导致问题。有没有办法可以禁用 OPTIONS 的要求授权? 【参考方案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 帖子中找到的
【讨论】:
据我所知,这只有在过滤器在安全过滤器链之前排序时才有效。【参考方案2】:正如 cmets 中所述,问题在于 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 boot 本身的安全自动配置。如果你只禁用 Activiti 的安全配置,Spring boot 的自动配置就会启动,你仍然可以在所有端点上进行身份验证。
但是,您可能仍希望在 Activiti 的某些端点上应用安全性,但这允许您自己自定义它,而不是依赖于自动配置。在您的情况下,您可以选择将安全性应用于 Activiti 正在使用的所有 /identity/**
、/management/**
、/history/**
、/repository/**
、/query/**
和 /runtime/**
路径。
选项 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
请求。您必须将req
和res
分别转换为HttpServletRequest
和HttpServletResponse
。
此外,您必须确保在安全过滤器链之前调用此过滤器。为此,请将CORSFilter
的顺序更改为选定的值,例如:
@Component
@Order(1) // You can choose the value yourself
public class CORSFilter implements Filter
// ...
现在通过将application.properties
中的security.filter-order
属性设置为更高的值来更改安全过滤器链顺序:
security.filter-order=2
【讨论】:
我尝试了选项 1。但它给了我同样的错误。我在我的应用程序上启用了调试模式,这就是我能看到的。名称为“dispatcherServlet”的 DispatcherServlet 正在处理 [/books/error] 的 OPTIONS 请求。当您尝试使用 POSTMAN 时,它如何返回正确的 url 那个端点是/books/error
,我猜它不属于/abc/**
匹配器?所以这可能是问题所在。
我暂时选择了选项 2。如果我想为某些 url 启用它,我是否必须为这些端点创建一个单独的安全配置?
如果他们没有类似的路径,可能是的。在这些情况下,最好选择选项 2 并定义自己的 SecurityConfig
来保护 Activiti 本身的路径。以上是关于Spring Boot CORS 过滤器不适用于 AngularJS的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot JWT Cors 不适用于 Angular 8