当请求的凭据模式为“包含"时,响应中的标头不得为通配符“*" [英] Header in the response must not be the wildcard '*' when the request's credentials mode is 'include'

查看:31
本文介绍了当请求的凭据模式为“包含"时,响应中的标头不得为通配符“*"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 Auth0 进行用户身份验证,只允许登录用户访问 Spring(引导)RestController.在这一点上,我正在创建一个实时消息功能,用户可以在其中将消息从 Angular 2 客户端 (localhost:4200) 发送到 Spring 服务器 (localhost:8081) 使用 stompjssockjs.

尝试创建 Stomp 客户端并开始连接时,我收到以下控制台错误:

 当请求的凭据模式为include"时,响应中Access-Control-Allow-Origin"标头的值不能是通配符*".因此,不允许访问 Origin 'http://localhost:4200'.XMLHttpRequest 发起的请求的凭证模式由 withCredentials 属性控制.

在研究这个问题之后,似乎不可能同时设置选项 origins = * 和 credentials = true .当我已将 WebSocketConfig 中允许的来源设置为客户端域时,如何解决此问题?

Angular 2 组件

connect() {var socket = new SockJS('http://localhost:8081/chat');this.stompClient = Stomp.over(socket);this.stompClient.connect({}, function(result) {console.log('已连接:' + 结果);this.stompClient.subscribe('/topic/messages', function(message) {控制台日志(消息);});});}

WebSocketConfig

@Configuration@EnableWebSocketMessageBroker公共类 WebSocketConfig 扩展 AbstractWebSocketMessageBrokerConfigurer {@覆盖公共无效 configureMessageBroker(MessageBrokerRegistry 配置){config.enableSimpleBroker("/topic");config.setApplicationDestinationPrefixes("/app");}@覆盖public void registerStompEndpoints(StompEndpointRegistry registry) {registry.addEndpoint("/chat").setAllowedOrigins("http://localhost:4200").withSockJS();}}

本地主机:8081/chat/info?t=1490866768565

{"entropy":-1720701276,"origins":["*:*"],"cookie_needed":true,"websocket":true}

消息控制器

public class MessageController {@MessageMapping("/聊天")@SendTo("/topic/messages")公共消息发送(消息消息)抛出异常{返回新消息(message.getFrom(), message.getText());}}

SecurityConfig(暂时允许所有)

 公共类 SecurityConfig 扩展 Auth0SecurityConfig {@覆盖protected void configure(HttpSecurity http) 抛出异常 {http.authorizeRequests().anyRequest().permitAll();}}

更新

经过更多的测试和研究,似乎问题只发生在 Chrome 上.问题可能与:

解决方案

问题:

您没有正确配置 'Access-Control-Allow-Origin',您当前的配置会被服务器忽略.

情况:

错误堆栈跟踪说明:

<块引用>

当请求的凭证模式为'include时,响应中'Access-Control-Allow-Origin'标头的值不能是通配符'*''.因此不允许访问源 'http://localhost:4200'.

这意味着除了您不能将 'Access-Control-Allow-Origin' 设置为通配符 "*" 之外,您的域 'http://localhost:4200' 也不允许访问.

回答您的问题:

<块引用>

如果我已经将 WebSocketConfig 中允许的来源设置为客户端域,我该如何解决这个问题?

解决方案:

我想您不需要在 WebSocketConfig 中设置允许的来源,因为它旨在按照 WebSocket 样式的消息传递="https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html" rel="noreferrer">Spring 文档中的WebSocket 支持a>,您需要在 CORSFilter 配置类中配置它,因为它旨在为 Web 应用程序访问配置 Spring 过滤器.

这是您在 CORSFilter.java 配置类中需要的:

公共类 CORSFilter 实现 Filter {//这将替换为允许访问服务器的域列表//您可以在此处包含多个来源私有最终列表allowedOrigins = Arrays.asList("http://localhost:4200");公共无效销毁(){}public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 抛出 IOException, ServletException {//让我们确保我们正在使用 HTTP(即,针对 HttpServletRequest 和 HttpServletResponse 对象)if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {HttpServletRequest request = (HttpServletRequest) req;HttpServletResponse 响应 = (HttpServletResponse) res;//访问控制允许来源String origin = request.getHeader("Origin");response.setHeader("Access-Control-Allow-Origin", allowedOrigins.contains(origin) ? origin : "");response.setHeader("Vary", "Origin");//访问控制最大年龄response.setHeader("Access-Control-Max-Age", "3600");//访问控制允许凭据response.setHeader("Access-Control-Allow-Credentials", "true");//访问控制允许方法response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");//访问控制允许标题response.setHeader("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept, " + "X-CSRF-TOKEN");}chain.doFilter(req, res);}公共无效初始化(FilterConfig filterConfig){}}

可以看到使用:

private final ListallowedOrigins = Arrays.asList("http://localhost:4200");

设置允许访问服务器的域列表.

参考:

你可能需要看看Spring 框架中的 CORS 支持启用交叉RESTful Web 服务的源请求以进一步阅读.

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.

When trying to create a Stomp-client and starting a connection I receive the following console-error:

 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?

Angular 2 component

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

{"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)

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

UPDATE

I created the CORSFilter like chsdk mentioned and used the addFilterBefore() method: 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:

解决方案

Problem:

You are not configuring 'Access-Control-Allow-Origin' correctly and your current configuration is simply ignored by the server.

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.

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.

To answer your question:

How can I resolve this when I've already set the allowed origin in the WebSocketConfig to the client domain?

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 applications as stated in WebSocket Support in 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.

This is what you will need in your CORSFilter.java configuration class:

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 Framework and Enabling Cross Origin Requests for a RESTful Web Service for further reading about it.

这篇关于当请求的凭据模式为“包含"时,响应中的标头不得为通配符“*"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆