我希望在服务器托管在ASP.NET WebAPI中时在SignalR中启用身份验证,我使用OAuth Bearer autrntication并且客户端是AngularJS。
在客户端,我最初通过HTTP标头传递Bearer令牌,它适用于WebAPI。但是由于SignalR JavsScript不支持在connection
中添加HTTP头(因为WebSocket不支持指定HTTP头),我需要通过查询字符串传递Bearer令牌。代码如self.connection.qs = { Bearer: 'xxxxxx' };
问题出在WebAPI方面,我的SignalR总是返回401 Unauthorized。
以下是我在WebAPI方面所做的工作。
1,我将OAuthBearerAuthenticationOptions.Provider
指定为QueryStringEnabledOAuthBearerAuthenticationProvider
,这是我从OAuthBearerAuthenticationProvider
继承的类,可以从查询字符串中检索Bearer令牌。代码如下。
public class QueryStringEnabledOAuthBearerAuthenticationProvider : OAuthBearerAuthenticationProvider { private readonly string _name; public QueryStringEnabledOAuthBearerAuthenticationProvider() : this(OAuthDefaults.AuthenticationType) { } public QueryStringEnabledOAuthBearerAuthenticationProvider(string name) { _name = name; } public override Task RequestToken(OAuthRequestTokenContext context) { // try to read token from base class (header) if possible base.RequestToken(context).Wait(); if (string.IsNullOrWhiteSpace(context.Token)) { // try to read token from query string var token = context.Request.Query.Get(_name); if (!string.IsNullOrWhiteSpace(token)) { context.Token = token; } } return Task.FromResult(null); } }
在WebAPI启动时将其注册如下。
var options = new OAuthBearerAuthenticationOptions { AuthenticationMode = AuthenticationMode.Active, AuthenticationType = AuthenticationType, Provider = new QueryStringEnabledOAuthBearerAuthenticationProvider(), AccessTokenFormat = _accessTokenFormat, }; config.SuppressDefaultHostAuthentication(); config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); app.UseOAuthBearerAuthentication(options);
2,在SignalR部分,我创建了一个authorize属性,如下所示。没有什么改变只是用来添加断点。
public class BearerAuthorizeAttribute : AuthorizeAttribute { public override bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request) { return base.AuthorizeHubConnection(hubDescriptor, request); } public override bool AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubIncomingInvokerContext, bool appliesToMethod) { return base.AuthorizeHubMethodInvocation(hubIncomingInvokerContext, appliesToMethod); } }
并在WebAPI启动时注册。
app.Map("/signalr", map => { // Setup the CORS middleware to run before SignalR. // By default this will allow all origins. You can // configure the set of origins and/or http verbs by // providing a cors options with a different policy. map.UseCors(CorsOptions.AllowAll); var hubConfiguration = new HubConfiguration { // You can enable JSONP by uncommenting line below. // JSONP requests are insecure but some older browsers (and some // versions of IE) require JSONP to work cross domain // EnableJSONP = true EnableJavaScriptProxies = false }; // Run the SignalR pipeline. We're not using MapSignalR // since this branch already runs under the "/signalr" // path. map.RunSignalR(hubConfiguration); // Require authentication for all hubs var authorizer = new BearerAuthorizeAttribute(); var module = new AuthorizeModule(authorizer, authorizer); GlobalHost.HubPipeline.AddModule(module); });
我发现,当SignalR连接时,我的QueryStringEnabledOAuthBearerAuthenticationProvider.RequestToken
被调用,并成功检索到了承载令牌。但是当调用SignalR BearerAuthorizeAttribute.AuthorizeHubConnection
时,参数request.User
仍然未经过身份验证。所以它返回401。
任何人都可以给我一些关于我做错了什么的想法,谢谢。
答案 0 :(得分:4)
我使用标题,这就是我解决它的方式
var authData = localStorageService.get('authorizationData');
var token = authData.token;
$.signalR.ajaxDefaults.headers = { Authorization: "Bearer " + token };
希望有所帮助
答案 1 :(得分:0)
我通过从AuthorizeAttribute中的查询字符串取消保护Bearer令牌来解决此问题,并将用户主体设置为新的ServerRequest。有关详细信息,请查看http://blog.shaunxu.me/archive/2014/05/27/set-context-user-principal-for-customized-authentication-in-signalr.aspx
这可能不是最好的解决方案,但它有效。