我使用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而只是设置请求标题但是感觉很脏......
有更清洁的方法吗?
我只是做些傻事吗?还有其他人参与其中吗?
答案 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>