我想在 SignalR 中启用身份验证,而服务器托管在 ASP.NET WebAPI 中,我使用 OAuth Bearer 身份验证,客户端是 AngularJS。
在客户端,我最初通过 HTTP 标头传递 Bearer 令牌,它与 WebAPI 配合良好。但由于 SignalR JavsScript 不支持在中添加 HTTP 标头connection
(这是因为 WebSocket 不支持指定 HTTP 标头)我需要使用以下代码通过查询字符串传递承载令牌self.connection.qs = { Bearer: 'xxxxxx' };
问题出在 WebAPI 端,我的 SignalR 总是返回 401 Unauthorized。
下面是我在 WebAPI 端所做的事情。
1、我指定OAuthBearerAuthenticationOptions.Provider
to QueryStringEnabledOAuthBearerAuthenticationProvider
,这是我创建的继承自的类OAuthBearerAuthenticationProvider
可以从查询字符串中检索承载令牌。代码如下。
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部分我创建了一个授权属性,如下所示。没有任何改变只是用来添加断点。
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
被调用并成功检索承载令牌。但是当 SignalRBearerAuthorizeAttribute.AuthorizeHubConnection
被调用参数request.User
仍然没有经过验证。所以它返回401。
谁能给我一些关于我做错了什么的想法,谢谢。