我有一个使用基本身份验证保护的 WebApi,它使用 AuthorizationFilterAttribute 应用于整个 Api。我的几个 Api Controller 上也有 SignalR 集线器。
除此之外,我还有一个使用我的 WebApi 的网页。网页大部分是用 Backbone 编写的,所以为了调用我的安全 WebApi,我添加了以下 jquery
$.ajaxSetup({
beforeSend: function (jqXHR, settings) {
jqXHR.setRequestHeader('Authorization', 'Basic ' + Token);
return true;
}
});
这适用于与我的 Api Controller 进行通信,但添加上述代码已断开与我的 SignalR 集线器的连接,特别是:
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 调用。
鉴于上述情况,我可以做一些骇人听闻的事情,并且仅在发出的请求不是/signalr 时才设置请求 header ,但这只是感觉很脏......
有没有更清洁的方法来解决这个问题?
我只是在做傻事吗?有没有其他人遇到过这个?
请您参考如下方法:
我之前没有提到的是我有一个 DelegatingHandler 它将正确的 header 发送回任何进入我的 WebApi 的请求。这适用于对我的 WebApi 的任何请求,但我错误地认为这也适用于 SignalR 请求。
由于 SignalR 依赖于几种不同的传输方法,因此假设我首先可以访问 Authorization header 似乎是不合理的 - 例如,它们不是所有 WebSockets 实现的要求(see here)
我目前的解决方案是使用 SignalR 的 HubPipeline (detailed here)。使用它,我相信我可以在查询字符串中传递基本身份验证凭据并编写一个单独的模块来处理 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 header 不是一个可靠的假设,出于上述原因,我仍在过滤我的 $.ajaxSetup 以仅影响非 SignalR 请求:
$.ajaxSetup({
beforeSend: function (jqXHR, settings) {
if (settings.url.indexOf("/signalr") == -1)
jqXHR.setRequestHeader('Authorization', 'Basic ' + Token);
return true;
}
});
在此过程中,我将让 SignalrBasicAuthFilterAttribute 类承担授权 SignalR 请求的全部责任。
延伸阅读: