Java 当请求的凭据模式为“包含”时,响应中的标头不得为通配符“*”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43114750/
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
Header in the response must not be the wildcard '*' when the request's credentials mode is 'include'
提问by Sam
I'm using Auth0
for my user authentication to only allow logged in users to access a Spring (Boot) RestController
. At this point I'm creating a real-time message functionality where users can send messages from the Angular 2
client (localhost:4200
) to the Spring server (localhost:8081) using stompjs
and sockjs
.
我使用Auth0
我的用户身份验证只允许登录用户访问 Spring (Boot) RestController
。在这一点上我创建一个实时信息功能,用户可以从发送邮件Angular 2
客户端(localhost:4200
)到春节服务器:使用(本地主机8081)stompjs
和sockjs
。
When trying to create a Stomp-client and starting a connection I receive the following console-error:
尝试创建 Stomp 客户端并开始连接时,我收到以下控制台错误:
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'. Origin 'http://localhost:4200' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
After researching this problem it looks like it is not possible to set the option origins = * and credentials = true at the same time. How can I resolve this when I've already set the allowed origin in the WebSocketConfig to the client domain?
在研究了这个问题之后,似乎不可能同时设置选项 origins = * 和 credentials = true 。当我已将 WebSocketConfig 中允许的来源设置为客户端域时,如何解决此问题?
Angular 2 component
Angular 2 组件
connect() {
var socket = new SockJS('http://localhost:8081/chat');
this.stompClient = Stomp.over(socket);
this.stompClient.connect({}, function(result) {
console.log('Connected: ' + result);
this.stompClient.subscribe('/topic/messages', function(message) {
console.log(message);
});
});
}
WebSocketConfig
网络套接字配置
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").setAllowedOrigins("http://localhost:4200").withSockJS();
}
}
localhost:8081/chat/info?t=1490866768565
本地主机:8081/chat/info?t=1490866768565
{"entropy":-1720701276,"origins":["*:*"],"cookie_needed":true,"websocket":true}
MessageController
消息控制器
public class MessageController {
@MessageMapping("/chat")
@SendTo("/topic/messages")
public Message send(Message message) throws Exception {
return new Message(message.getFrom(), message.getText());
}
}
SecurityConfig (temporarily permits all)
SecurityConfig(暂时允许所有)
public class SecurityConfig extends Auth0SecurityConfig {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().permitAll();
}
}
UPDATE
更新
After some more testing and researching it seems that the problem only happens using Chrome. Problem maybe related to: https://github.com/sockjs/sockjs-node/issues/177
经过一些更多的测试和研究,问题似乎只发生在 Chrome 上。问题可能与:https: //github.com/sockjs/sockjs-node/issues/177有关
UPDATE
更新
I created the CORSFilter like chsdk mentioned and used the addFilterBefore() method: https://stackoverflow.com/a/40300363/4836952.
我创建了像 chsdk 提到的 CORSFilter 并使用了 addFilterBefore() 方法:https://stackoverflow.com/a/40300363/4836952 。
@Bean
CORSFilter corsFilter() {
CORSFilter filter = new CORSFilter();
return filter;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(corsFilter(), SessionManagementFilter.class).authorizeRequests().anyRequest().permitAll();
http.csrf().disable();
}
I can see that the Filter is called by debugging it but the error message keeps appearing on the clientside even if the correct Access-Control-Allow-Origin gets set:
我可以看到过滤器是通过调试来调用的,但是即使设置了正确的 Access-Control-Allow-Origin,错误消息仍然出现在客户端:
采纳答案by cн?dk
Problem:
问题:
You are not configuring 'Access-Control-Allow-Origin'
correctly and your current configuration is simply ignored by the server.
您没有'Access-Control-Allow-Origin'
正确配置,服务器只是忽略了您当前的配置。
Situation:
情况:
The Error stack trace says:
错误堆栈跟踪说:
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'. Origin 'http://localhost:4200' is therefore not allowed access.
当请求的凭证模式为“包含”时
'Access-Control-Allow-Origin'
,响应中标头的值不能是通配符'*'
。因此,不允许访问Origin ' http://localhost:4200'。
It means that apart from the fact that you can't set 'Access-Control-Allow-Origin'
to the wildcard "*"
, your domain 'http://localhost:4200'
is not allowed access too.
这意味着除了您不能设置'Access-Control-Allow-Origin'
为通配符之外"*"
,您的域'http://localhost:4200'
也不允许访问。
To answer your question:
回答你的问题:
How can I resolve this when I've already set the allowed origin in the WebSocketConfig to the client domain?
当我已将 WebSocketConfig 中允许的来源设置为客户端域时,如何解决此问题?
Solution:
解决方案:
I guess you don't need to set the allowed origin in the WebSocketConfig
because it's meant to configure WebSocket-style messaging in web applicationsas stated in WebSocket Supportin Spring documentation, you will need to configure it in a CORSFilter
configuration class as it's meant to configure Spring Filters for Web application access.
我猜您不需要在中设置允许的来源,WebSocketConfig
因为它旨在按照 Spring 文档中的WebSocket 支持中所述在Web 应用程序中配置WebSocket 样式的消息传递,您需要在配置类中配置它,因为它旨在配置用于 Web 应用程序访问的 Spring 过滤器。CORSFilter
This is what you will need in your CORSFilter.java
configuration class:
这是您在CORSFilter.java
配置类中需要的:
public class CORSFilter implements Filter {
// This is to be replaced with a list of domains allowed to access the server
//You can include more than one origin here
private final List<String> allowedOrigins = Arrays.asList("http://localhost:4200");
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
// Lets make sure that we are working with HTTP (that is, against HttpServletRequest and HttpServletResponse objects)
if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// Access-Control-Allow-Origin
String origin = request.getHeader("Origin");
response.setHeader("Access-Control-Allow-Origin", allowedOrigins.contains(origin) ? origin : "");
response.setHeader("Vary", "Origin");
// Access-Control-Max-Age
response.setHeader("Access-Control-Max-Age", "3600");
// Access-Control-Allow-Credentials
response.setHeader("Access-Control-Allow-Credentials", "true");
// Access-Control-Allow-Methods
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
// Access-Control-Allow-Headers
response.setHeader("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, " + "X-CSRF-TOKEN");
}
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {
}
}
You can see the use of :
你可以看到使用:
private final List<String> allowedOrigins = Arrays.asList("http://localhost:4200");
To set the list of domains allowed to access the server.
设置允许访问服务器的域列表。
References:
参考:
You may need to take a look at CORS support in Spring Frameworkand Enabling Cross Origin Requests for a RESTful Web Servicefor further reading about it.
您可能需要查看Spring Framework中的CORS 支持和启用 RESTful Web 服务的跨源请求以进一步阅读。
回答by VikingCode
This has nothing to do with your spring or angular app code.
这与您的 spring 或 angular 应用程序代码无关。
Intro to your problem
The Access-Control-Allow-Originis a part of CORS (Cross-Origin Resource Sharing)mechanism that gives web servers cross-domain access controls. It is in place to protect your app/site from CSRF (Cross-Site Request Forgery).
介绍给你的问题
的访问控制允许来源是CORS的一部分(跨来源资源共享)机制,让Web服务器跨域访问控制。它可以保护您的应用程序/站点免受 CSRF (跨站点请求伪造)的侵害。
The problem
Now if we read your error carefully
问题
现在如果我们仔细阅读你的错误
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'.
Origin 'http://localhost:4200' is therefore not allowed access.
It says that Access-Control-Allow-Originheader cannot be a wildcard.
它说Access-Control-Allow-Origin标头不能是通配符。
With other words, now your back-end is saying everybody from allover the web can run code on my site.
换句话说,现在您的后端说来自整个网络的每个人都可以在我的网站上运行代码。
What we want to achieve: Limit the origin to only your front-end app (ng2).
我们想要实现的目标:将源限制为仅您的前端应用程序 (ng2)。
SolutionNow because you are using Spring I will assume that you are using it with Apache Tomcat as your back-end webserver.
解决方案现在,因为您使用的是 Spring,我将假设您将它与 Apache Tomcat 作为后端 Web 服务器一起使用。
CORS are difined as filter in your web.conf (tomcat folder)
CORS 在 web.conf(tomcat 文件夹)中定义为过滤器
find this line
找到这一行
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>*</param-value>
</init-param>
and change the * to http://localhost:4200
并将 * 更改为http://localhost:4200
for more information about config of CORS in Tomcat please read this
有关 Tomcat 中 CORS 配置的更多信息,请阅读此内容
EDIT( Spring boot )
Because you are using spring boot, you can delegate configuration of cors to the framework.
EDIT( Spring boot )
因为您使用的是 spring boot,所以您可以将 cors 的配置委托给框架。
Please follow this tutorial on spring.io( like chsdk proposed )to get a better grasp of CORS configuration with spring boot .
请按照spring.io上的本教程(如建议的 chsdk)来更好地掌握使用 spring 引导的 CORS 配置。
回答by Wentao Wan
Just add .setAllowedOrigins("*")
at webSocket config.
只需.setAllowedOrigins("*")
在 webSocket 配置中添加。
@Override
public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry.addEndpoint("/yourEndpoint");
stompEndpointRegistry.addEndpoint("/yourEndpoint").setAllowedOrigins("*").withSockJS();
}
The version of webSocket is 1.4.1.RELEASE,you should update your version if the method wasn't shown.
webSocket 的版本是 1.4.1.RELEASE,如果方法没有显示,你应该更新你的版本。
回答by BenFarhat Souhaib
my answer is too late but i'm posting this if anyone could face the same problem, i've been facing the same cross-origin issue.
我的回答为时已晚,但如果有人遇到同样的问题,我会发布此信息,我一直面临着相同的跨域问题。
Basically if you are using Spring Security implemented on your server side application, Probably it is he who blocks websocket handshaker
基本上,如果您使用在服务器端应用程序上实现的 Spring Security,可能是他阻止了 websocket 握手
You have to tell Spring security to allow your websocket endpoints in order to allow socket handshake...using
您必须告诉 Spring security 允许您的 websocket 端点以允许套接字握手...使用
.antMatchers("/socket/**").permitAll()
So sockjs will be able now to send a GET (Http) request for handshaking before switching to Websocket protocol
所以 sockjs 现在可以在切换到 Websocket 协议之前发送 GET (Http) 请求以进行握手
This is Spring security Configuration
这是 Spring 安全配置
package org.souhaib.caremy.security.module.config;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint).and()
.authorizeRequests()
.antMatchers(SecurityParams.PUBLIC_ROUTES).permitAll()
.antMatchers("/socket/**").permitAll();
http.csrf().disable();
}}
This is WebSocket Broker configuration
这是 WebSocket Broker 配置
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/socket")
.setAllowedOrigins("http://localhost:4200")
.withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app")
.enableSimpleBroker("/chat");
}
}