使用ajaxSetup beforeSend进行Basic Auth会破坏SignalR连接

时间:2013-04-24 10:55:29

标签: ajax asp.net-web-api authorization signalr basic-authentication

我使用Basic Auth保护WebApi,使用AuthorizationFilterAttribute将其应用于整个Api。我还有几个Api控制器上的SignalR Hubs。

除此之外,我还有一个使用WebApi的网页。该网页主要是用Backbone编写的,所以为了调用我的安全WebApi,我添加了以下jquery

$.ajaxSetup({
    beforeSend: function (jqXHR, settings) {
        jqXHR.setRequestHeader('Authorization', 'Basic ' + Token);
        return true;
    }
});

这适用于与我的Api控制器进行通信,但添加上述代码已经破坏了与SignalR Hub的连接,特别是:

XMLHttpRequest cannot load http://localhost:50000/signalr/negotiate?_=1366795855194. 
Request header field Authorization is not allowed by Access-Control-Allow-Headers. 

删除jqXHR.setRequestHeader()行会恢复我的SignalR Hub连接,但会中断Api呼叫。

鉴于上述情况,我可以做一些hacky并且如果正在发出的请求不是/ signalr而只是设置请求标题但是感觉很脏......

有更清洁的方法吗?

我只是做些傻事吗?还有其他人参与其中吗?

2 个答案:

答案 0 :(得分:7)

我之前没有提到的是我有一个DelegatingHandler,它会将正确的Headers发送回任何进入我的WebApi的请求。这适用于对WebApi的任何请求,但我错误地认为这也适用于SignalR请求。

由于SignalR依赖于几种不同的传输方法,因此假设我首先可以访问授权标头似乎是不合理的 - 例如,它们不是所有WebSockets实现的要求(see here

我目前的解决方案是使用SignalR的HubPipeline(detailed here)。使用这个,我相信我可以在查询字符串中传递Basic Auth凭证,并编写一个单独的模块来处理SignalR请求的授权:


传递查询字符串

$.connection.hub.qs = "auth=" + MyBase64EncodedAuthString;

过滤器

public class SignalrBasicAuthFilterAttribute: Attribute, IAuthorizeHubConnection {

    public bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request) {
      var authString = request.QueryString["auth"];

      // ... parse, authorize, etc ...

      return true;
    }

}

注册过滤器

var globalAuthorizer = new SignalrBasicAuthFilterAttribute();
GlobalHost.HubPipeline.AddModule(new AuthorizeModule(globalAuthorizer, globalAuthorizer));

<强>另外...

请注意,因为使用SignalR请求发送Authorization标头不是一个可靠的假设,出于上述原因,我仍在过滤$ .ajaxSetup以仅影响非SignalR 请求:

$.ajaxSetup({
    beforeSend: function (jqXHR, settings) {
        if (settings.url.indexOf("/signalr") == -1)
            jqXHR.setRequestHeader('Authorization', 'Basic ' + Token);
        return true;
    }
});

在执行此操作时,我将离开SignalrBasicAuthFilterAttribute类,以承担授权SignalR请求的全部责任。


进一步阅读:

答案 1 :(得分:1)

我认为该问题的真正解决方案是确保“授权”是“negotiate”请求的signalR响应返回的允许标头(Access-Control-Allow-Headers)的一部分。

您可以在web.config中注册标题,就像这种可能性一样。

<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Headers" value="Authorization" />
  </customHeaders>
</httpProtocol>