Java 使用 Spring Security 实现跨域资源共享
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18264334/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Cross-Origin Resource Sharing with Spring Security
提问by Aram Kocharyan
I'm trying to make CORS play nicely with Spring Security but it's not complying. I made the changes described in this articleand changing this line in applicationContext-security.xml
has got POST and GET requests working for my app (temporarily exposes controller methods, so I can test CORS):
我试图让 CORS 与 Spring Security 一起很好地发挥作用,但它不符合要求。我进行了本文中描述的更改,并更改了这一行,applicationContext-security.xml
使 POST 和 GET 请求适用于我的应用程序(暂时公开控制器方法,因此我可以测试 CORS):
- Before:
<intercept-url pattern="/**" access="isAuthenticated()" />
- After:
<intercept-url pattern="/**" access="permitAll" />
- 前:
<intercept-url pattern="/**" access="isAuthenticated()" />
- 后:
<intercept-url pattern="/**" access="permitAll" />
Unfortunately the following URL which allows Spring Security logins through AJAX isn't responding: http://localhost:8080/mutopia-server/resources/j_spring_security_check
. I am making the AJAX request from http://localhost:80
to http://localhost:8080
.
不幸的是,下面的URL允许通过AJAX春季安全登录不响应:http://localhost:8080/mutopia-server/resources/j_spring_security_check
。我正在从http://localhost:80
to发出 AJAX 请求http://localhost:8080
。
In Chrome
在 Chrome 中
When attempting to access j_spring_security_check
I get (pending)
in Chrome for the OPTIONS preflight request and AJAX call returns with HTTP status code 0 and message "error".
尝试访问时,j_spring_security_check
我进入(pending)
Chrome 以获取 OPTIONS 预检请求,并且 AJAX 调用返回 HTTP 状态代码 0 和消息“错误”。
In Firefox
在火狐浏览器中
The preflight succeeds with HTTP status code 302 and I still get the error callback for my AJAX request directly afterwards with HTTP status 0 and message "error".
预检成功,HTTP 状态代码为 302,之后我仍然直接收到 AJAX 请求的错误回调,HTTP 状态为 0 和消息“错误”。
AJAX Request Code
AJAX 请求代码
function get(url, json) {
var args = {
type: 'GET',
url: url,
// async: false,
// crossDomain: true,
xhrFields: {
withCredentials: false
},
success: function(response) {
console.debug(url, response);
},
error: function(xhr) {
console.error(url, xhr.status, xhr.statusText);
}
};
if (json) {
args.contentType = 'application/json'
}
$.ajax(args);
}
function post(url, json, data, dataEncode) {
var args = {
type: 'POST',
url: url,
// async: false,
crossDomain: true,
xhrFields: {
withCredentials: false
},
beforeSend: function(xhr){
// This is always added by default
// Ignoring this prevents preflight - but expects browser to follow 302 location change
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.setRequestHeader("X-Ajax-call", "true");
},
success: function(data, textStatus, xhr) {
// var location = xhr.getResponseHeader('Location');
console.error('success', url, xhr.getAllResponseHeaders());
},
error: function(xhr) {
console.error(url, xhr.status, xhr.statusText);
console.error('fail', url, xhr.getAllResponseHeaders());
}
}
if (json) {
args.contentType = 'application/json'
}
if (typeof data != 'undefined') {
// Send JSON raw in the body
args.data = dataEncode ? JSON.stringify(data) : data;
}
console.debug('args', args);
$.ajax(args);
}
var loginJSON = {"j_username": "username", "j_password": "password"};
// Fails
post('http://localhost:8080/mutopia-server/resources/j_spring_security_check', false, loginJSON, false);
// Works
post('http://localhost/mutopia-server/resources/j_spring_security_check', false, loginJSON, false);
// Works
get('http://localhost:8080/mutopia-server/landuses?projectId=6', true);
// Works
post('http://localhost:8080/mutopia-server/params', true, {
"name": "testing",
"local": false,
"generated": false,
"project": 6
}, true);
Please note - I can POST to any other URL in my app via CORS except the Spring Security login. I've gone through lots of articles, so any insight into this strange issue would be greatly appreciated
请注意 - 除了 Spring Security 登录名之外,我可以通过 CORS 发布到我的应用程序中的任何其他 URL。我已经阅读了很多文章,因此对这个奇怪问题的任何见解都将不胜感激
采纳答案by Keeth
I was able to do this by extending UsernamePasswordAuthenticationFilter... my code is in Groovy, hope that's OK:
我能够通过扩展 UsernamePasswordAuthenticationFilter 来做到这一点......我的代码在 Groovy 中,希望没问题:
public class CorsAwareAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
static final String ORIGIN = 'Origin'
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response){
if (request.getHeader(ORIGIN)) {
String origin = request.getHeader(ORIGIN)
response.addHeader('Access-Control-Allow-Origin', origin)
response.addHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE')
response.addHeader('Access-Control-Allow-Credentials', 'true')
response.addHeader('Access-Control-Allow-Headers',
request.getHeader('Access-Control-Request-Headers'))
}
if (request.method == 'OPTIONS') {
response.writer.print('OK')
response.writer.flush()
return
}
return super.attemptAuthentication(request, response)
}
}
The important bits above:
上面的重要部分:
- Only add CORS headers to response if CORS request detected
- Respond to pre-flight OPTIONS request with a simple non-empty 200 response, which also contains the CORS headers.
- 如果检测到 CORS 请求,则仅将 CORS 标头添加到响应中
- 使用简单的非空 200 响应响应飞行前 OPTIONS 请求,其中还包含 CORS 标头。
You need to declare this bean in your Spring configuration. There are many articles showing how to do this so I won't copy that here.
您需要在 Spring 配置中声明这个 bean。有很多文章展示了如何做到这一点,所以我不会在这里复制。
In my own implementation I use an origin domain whitelist as I am allowing CORS for internal developer access only. The above is a simplified version of what I am doing so may need tweaking but this should give you the general idea.
在我自己的实现中,我使用原始域白名单,因为我只允许内部开发人员访问 CORS。以上是我正在做的事情的简化版本,可能需要调整,但这应该给你一个大致的想法。
回答by azerafati
well This is my code working very well and perfect for me: I spent two days working on it and understanding spring security so I hope you accept it as the answer, lol
好吧,这是我的代码运行良好,对我来说非常完美:我花了两天时间研究它并了解 spring 安全性,所以我希望你接受它作为答案,大声笑
public class CorsFilter extends OncePerRequestFilter {
static final String ORIGIN = "Origin";
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
System.out.println(request.getHeader(ORIGIN));
System.out.println(request.getMethod());
if (request.getHeader(ORIGIN).equals("null")) {
String origin = request.getHeader(ORIGIN);
response.setHeader("Access-Control-Allow-Origin", "*");//* or origin as u prefer
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers",
request.getHeader("Access-Control-Request-Headers"));
}
if (request.getMethod().equals("OPTIONS")) {
try {
response.getWriter().print("OK");
response.getWriter().flush();
} catch (IOException e) {
e.printStackTrace();
}
}else{
filterChain.doFilter(request, response);
}
}
}
well then you need to also set your filter to be invoked:
那么您还需要设置要调用的过滤器:
<security:http use-expressions="true" .... >
...
//your other configs
<security:custom-filter ref="corsHandler" after="PRE_AUTH_FILTER"/> // this goes to your filter
</security:http>
Well and you need a bean for the custom filter you created:
好吧,您需要为您创建的自定义过滤器添加一个 bean:
<bean id="corsHandler" class="mobilebackbone.mesoft.config.CorsFilter" />
回答by Mathias G.
I totally agree with the answer given by Bludream, but I have some remarks:
我完全同意 Bludream 给出的答案,但我有一些评论:
I would extend the if clause in the CORS filter with a NULL check on the origin header:
我会扩展 CORS 过滤器中的 if 子句,并对原始标头进行 NULL 检查:
public class CorsFilter extends OncePerRequestFilter {
private static final String ORIGIN = "Origin";
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (request.getHeader(ORIGIN) == null || request.getHeader(ORIGIN).equals("null")) {
response.addHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.addHeader("Access-Control-Max-Age", "10");
String reqHead = request.getHeader("Access-Control-Request-Headers");
if (!StringUtils.isEmpty(reqHead)) {
response.addHeader("Access-Control-Allow-Headers", reqHead);
}
}
if (request.getMethod().equals("OPTIONS")) {
try {
response.getWriter().print("OK");
response.getWriter().flush();
} catch (IOException e) {
e.printStackTrace();
}
} else{
filterChain.doFilter(request, response);
}
}
}
Furthermore, I noticed the following unwanted behavior: If I try to access a REST API with an unauthorized role, Spring security returns me an HTTP status 403: FORBIDDEN and the CORS headers are returned. However, if I use an unknown token, or a token that isn't valid anymore, an HTTP status 401: UNAUTHORIZED is returned WITHOUT CORS headers.
此外,我注意到以下不需要的行为:如果我尝试使用未经授权的角色访问 REST API,Spring 安全性会返回一个 HTTP 状态 403: FORBIDDEN 并返回 CORS 标头。但是,如果我使用未知令牌或不再有效的令牌,则会返回 HTTP 状态 401: UNAUTHORIZED 不带 CORS 标头。
I managed to make it work by changing the filter configuration in the security XML like this:
我设法通过更改安全 XML 中的过滤器配置来使其工作,如下所示:
<security:http use-expressions="true" .... >
...
//your other configs
<sec:custom-filter ref="corsFilter" before="HEADERS_FILTER"/>
</security:http>
And the following bean for our custom filter:
以及用于我们的自定义过滤器的以下 bean:
<bean id="corsFilter" class="<<location of the CORS filter class>>" />
回答by Ajinath
In my case, response.getWriter().flush() was't working
就我而言, response.getWriter().flush() 不起作用
Changed the code as below and it started working
更改代码如下,它开始工作
public void doFilter(ServletRequest request, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
LOGGER.info("Start API::CORSFilter");
HttpServletRequest oRequest = (HttpServletRequest) request;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST,PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers",
" Origin, X-Requested-With, Content-Type, Accept,AUTH-TOKEN");
if (oRequest.getMethod().equals("OPTIONS")) {
response.flushBuffer();
} else {
chain.doFilter(request, response);
}
}
回答by Anthony De Smet
For me, the problem was that the OPTIONS
preflight check failed authentication, because the credentials weren't passed on that call.
对我来说,问题在于OPTIONS
预检检查未通过身份验证,因为凭据未在该调用中传递。
This works for me:
这对我有用:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.data.web.config.EnableSpringDataWebSupport;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Configuration
@EnableAsync
@EnableScheduling
@EnableSpringDataWebSupport
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.httpBasic().and()
.authorizeRequests()
.anyRequest().authenticated()
.and().anonymous().disable()
.exceptionHandling().authenticationEntryPoint(new BasicAuthenticationEntryPoint() {
@Override
public void commence(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException authException) throws IOException, ServletException {
if(HttpMethod.OPTIONS.matches(request.getMethod())){
response.setStatus(HttpServletResponse.SC_OK);
response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, request.getHeader(HttpHeaders.ORIGIN));
response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, request.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS));
response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, request.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD));
response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
}else{
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
}
}
});
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
}
The relevant part being:
相关部分是:
.exceptionHandling().authenticationEntryPoint(new BasicAuthenticationEntryPoint() {
@Override
public void commence(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException authException) throws IOException, ServletException {
if(HttpMethod.OPTIONS.matches(request.getMethod())){
response.setStatus(HttpServletResponse.SC_OK);
response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, request.getHeader(HttpHeaders.ORIGIN));
response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, request.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS));
response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, request.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD));
response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
}else{
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
}
}
});
That fixes the OPTIONS
preflight issue. What happens here is when you receive a call and authentication fails, you check if it's an OPTIONS
call and if it is, just let it pass and let it do everything it wants to do. This essentially disables all browser-side preflight checking, but normal crossdomain policy still applies.
这解决了OPTIONS
预检问题。这里发生的事情是,当您收到一个呼叫并且身份验证失败时,您检查它是否是一个OPTIONS
呼叫,如果是,就让它通过并让它做它想做的一切。这实质上禁用了所有浏览器端预检检查,但正常的跨域策略仍然适用。
When you're using the latest version of Spring, you can use the code below to allow cross origin requests globally (for all your controllers):
当您使用最新版本的 Spring 时,您可以使用下面的代码来允许全局跨域请求(对于您的所有控制器):
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Component
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:3000");
}
}
Note that this is rarely a good idea to just hard code it like this. In a few companies I've worked for, the allowed origins were configurable through an admin portal, so on development environments you would be able to add all the origins you need.
请注意,像这样对其进行硬编码很少是一个好主意。在我工作过的几家公司中,允许的来源可通过管理门户进行配置,因此在开发环境中,您可以添加所需的所有来源。
回答by nolan4954
Mostly,the OPTIONS request dont carry cookie for the authentication of the spring security.
To resovle that,can modify configuration of spring security to allow OPTIONSrequest without authentication.
I research a lot and get two solutions:
1.Using Java config with spring security configuration,
大多数情况下,OPTIONS 请求不携带用于 spring 安全性认证的 cookie。
要解决这个问题,可以修改 spring security 的配置以允许OPTIONS请求而无需身份验证。
我研究了很多,得到了两种解决方案:
1.使用带有 spring 安全配置的 Java 配置,
@Override
protected void configure(HttpSecurity http) throws Exception
{
http
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS,"/path/to/allow").permitAll()//allow CORS option calls
.antMatchers("/resources/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic();
}
2.Using XML(note.cant not write "POST,GET"):
2.使用XML(注意不能写“POST,GET”):
<http auto-config="true">
<intercept-url pattern="/client/edit" access="isAuthenticated" method="GET" />
<intercept-url pattern="/client/edit" access="hasRole('EDITOR')" method="POST" />
<intercept-url pattern="/client/edit" access="hasRole('EDITOR')" method="GET" />
</http>
On the end,there is the source for the solution...:)
最后,有解决方案的来源......:)
回答by Hendy Irawan
Since Spring Security 4.1, this is the proper way to make Spring Security support CORS (also needed in Spring Boot 1.4/1.5):
从 Spring Security 4.1 开始,这是使 Spring Security 支持 CORS 的正确方法(Spring Boot 1.4/1.5 中也需要):
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
}
}
and:
和:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// http.csrf().disable();
http.cors();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(ImmutableList.of("*"));
configuration.setAllowedMethods(ImmutableList.of("HEAD",
"GET", "POST", "PUT", "DELETE", "PATCH"));
// setAllowCredentials(true) is important, otherwise:
// The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
configuration.setAllowCredentials(true);
// setAllowedHeaders is important! Without it, OPTIONS preflight request
// will fail with 403 Invalid CORS request
configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
Do notdo any of below, which are the wrong way to attempt solving the problem:
千万不能做任何的下方,这是错误的方式来尝试解决问题:
http.authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll();
web.ignoring().antMatchers(HttpMethod.OPTIONS);
http.authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll();
web.ignoring().antMatchers(HttpMethod.OPTIONS);
Reference: http://docs.spring.io/spring-security/site/docs/4.2.x/reference/html/cors.html
参考:http: //docs.spring.io/spring-security/site/docs/4.2.x/reference/html/cors.html
回答by Дмитрий Кулешов
Since main part of question is about unathorized CORS POST-request to login point I immediately point you to step 2.
由于问题的主要部分是关于登录点未经授权的 CORS POST 请求,我立即将您指向第2步。
But regarding to answers count this is the most relevant question to Spring Security CORSrequest. So I will describe more elegant solution for configuring CORS with Spring Security. Because except rare situations it is not necessary to create filters/interceptors/… to put anything in response. We will do that declaratively by Spring. Since Spring Framework 4.2 we have CORS-stuff like filter, processor, etc out-of-the-box. And some links to read 12.
但是关于答案计数,这是与Spring Security CORS请求最相关的问题。因此,我将描述使用 Spring Security 配置 CORS 的更优雅的解决方案。因为除了极少数情况之外,没有必要创建过滤器/拦截器/......来做出任何反应。我们将在 Spring 中以声明方式执行此操作。从 Spring Framework 4.2 开始,我们有了开箱即用的 CORS 东西,如过滤器、处理器等。以及一些阅读1 2 的链接。
Let's go:
我们走吧:
1. prepare CORS configuration source.
1.准备CORS配置源。
It can be done in different ways:
它可以通过不同的方式完成:
as global Spring MVC CORS config (in configuration classes like
WebMvcConfigurerAdapter
)... @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") ... }
as separate
corsConfigurationSource
bean@Bean CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); config.applyPermitDefaultValues(); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); }
as external class (which can be used via constructor or autowired as a component)
// @Component // <- for autowiring class CorsConfig extends UrlBasedCorsConfigurationSource { CorsConfig() { orsConfiguration config = new CorsConfiguration(); config.applyPermitDefaultValues(); // <- frequantly used values this.registerCorsConfiguration("/**", config); } }
作为全局 Spring MVC CORS 配置(在配置类中
WebMvcConfigurerAdapter
)... @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") ... }
作为单独的
corsConfigurationSource
豆@Bean CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); config.applyPermitDefaultValues(); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); }
作为外部类(可以通过构造函数使用或作为组件自动装配)
// @Component // <- for autowiring class CorsConfig extends UrlBasedCorsConfigurationSource { CorsConfig() { orsConfiguration config = new CorsConfiguration(); config.applyPermitDefaultValues(); // <- frequantly used values this.registerCorsConfiguration("/**", config); } }
2. enable CORS support with the defined configuration
2. 使用定义的配置启用 CORS 支持
We will enable CORS support in Spring Security classes like WebSecurityConfigurerAdapter
. Be sure that corsConfigurationSource
is accessible for this support.
Else provide it via @Resource
autowiring or set explicitly (see in example).
Also we let unauthorized access to some endpoints like login:
我们将在 Spring Security 类中启用 CORS 支持,例如WebSecurityConfigurerAdapter
. 确保corsConfigurationSource
可以访问此支持。否则通过@Resource
自动装配或显式设置提供它(参见示例)。我们还允许未经授权访问某些端点,例如登录:
...
// @Resource // <- for autowired solution
// CorseConfigurationSource corsConfig;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors();
// or autowiring
// http.cors().configurationSource(corsConfig);
// or direct set
// http.cors().configurationSource(new CorsConfig());
http.authorizeRequests()
.antMatchers("/login").permitAll() // without this line login point will be unaccessible for authorized access
.antMatchers("/*").hasAnyAuthority(Authority.all()); // <- all other security stuff
}
3. customize CORS config
3.自定义CORS配置
If base config works then we can customize mappings, origins, etc. Even add several configurations for different mappings. For example, I explicitly declare all CORS parameters and let UrlPathHelper to not trim my servlet path:
如果基本配置有效,那么我们可以自定义映射、来源等。甚至可以为不同的映射添加多个配置。例如,我明确声明所有 CORS 参数并让 UrlPathHelper 不修剪我的 servlet 路径:
class RestCorsConfig extends UrlBasedCorsConfigurationSource {
RestCorsConfig() {
this.setCorsConfigurations(Collections.singletonMap("/**", corsConfig()));
this.setAlwaysUseFullPath(true);
}
private static CorsConfiguration corsConfig() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedHeader("*");
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
config.setAllowCredentials(true);
config.addAllowedOrigin("*");
config.setMaxAge(3600L);
return config;
}
}
4. troubleshooting
4. 故障排除
To debug my problem I was tracing org.springframework.web.filter.CorsFilter#doFilterInternal
method.
And I saw that CorsConfiguration search returns null
because Spring MVC global CORS configuration was unseen by Spring Security.
So I used solution with direct usage of external class:
为了调试我的问题,我正在跟踪org.springframework.web.filter.CorsFilter#doFilterInternal
方法。我看到 CorsConfiguration 搜索返回,null
因为 Spring Security 没有看到Spring MVC 全局 CORS 配置。所以我使用了直接使用外部类的解决方案:
http.cors().configurationSource(corsConfig);