Spring Security拦截器引起Java CORS跨域失败的问题及解决
在使用Spring Security进行接口保护的时候,经常会遇到因为跨域问题导致前端无法访问服务器接口的问题。本文将详细介绍Spring Security拦截器引起Java CORS跨域失败的问题及解决。
什么是CORS跨域
CORS(Cross-Origin Resource Sharing)即跨域资源共享,是一种用于跨域访问资源的机制。当一个域的JavaScript代码向另外一个域发送请求时,就会触发跨域。由于JavaScript的同源策略限制,这时的请求会被终止。
Spring Security拦截器引起Java CORS跨域失败的问题
Spring Security使用拦截器来保护接口,如果没有正确配置,就会导致跨域请求失败。具体表现为前端向服务器发送请求时,收到错误提示:
Access to XMLHttpRequest at 'http://example.com/api/someapi' from origin 'http://localhost:8080'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested
resource.
这是因为服务器拦截器不允许来自不同域的请求。具体来说,是因为在服务器端请求头缺少Access-Control-Allow-Origin
字段。如果在前端代码中添加这个字段,就可以通过CORS跨域访问接口。但是由于拦截器的存在,这并不是一个解决办法。
解决Spring Security拦截器引起Java CORS跨域失败的问题
要解决Spring Security拦截器引起Java CORS跨域失败的问题,可以采用以下步骤。
步骤1:添加Filter
在Server端添加一个过滤器,如下所示:
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
@Override
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, OPTIONS, DELETE, PUT");
response.setHeader("Access-Control-Allow-Headers",
"Authorization, Content-Type, Accept, X-Requested-With, Origin, Access-Control-Request-Method, Access-Control-Request-Headers");
response.setHeader("Access-Control-Expose-Headers", "Access-Control-Allow-Origin,Access-Control-Allow-Credentials");
chain.doFilter(req, res);
}
@Override
public void destroy() {}
@Override
public void init(FilterConfig config) throws ServletException {}
}
这个过滤器会在请求进入拦截器前执行,并添加CORS信息。
步骤2:配置Spring Security
在SecurityConfig类中添加以下代码:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/**").permitAll()
.anyRequest().authenticated()
.and().csrf().disable();
http.addFilterBefore(corsFilter, ChannelProcessingFilter.class);
}
这里的api/**
是需要允许跨域访问的接口路径,.antMatchers("/api/**").permitAll()
的意思是对这些接口不进行权限验证。
这样就可以解决Spring Security拦截器引起Java CORS跨域失败的问题了。
示例1:允许所有的请求跨域
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
@Override
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, OPTIONS, DELETE, PUT");
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept");
response.setHeader("Access-Control-Expose-Headers", "Access-Control-Allow-Origin,Access-Control-Allow-Credentials");
chain.doFilter(req, res);
}
@Override
public void destroy() {}
@Override
public void init(FilterConfig config) throws ServletException {}
}
以上代码的作用是允许所有的请求跨域,通常不建议使用,因为这会导致服务器存在安全风险。
示例2:只允许指定域名的请求跨域
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String origin = request.getHeader("Origin");
if (origin != null && (origin.contains("example.com") || origin.contains("example.cn"))) {
response.setHeader("Access-Control-Allow-Origin", origin);
}
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept");
response.setHeader("Access-Control-Expose-Headers", "Access-Control-Allow-Origin,Access-Control-Allow-Credentials");
chain.doFilter(req, res);
}
@Override
public void destroy() {}
@Override
public void init(FilterConfig config) throws ServletException {}
}
以上代码的作用是只允许来自example.com
或example.cn
的域名请求跨域。如果请求的域名不在白名单中,服务器会拒绝该请求。这样做可以有效地防止跨站点伪造请求(CSRF)。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring Security拦截器引起Java CORS跨域失败的问题及解决 - Python技术站