我想在 SignalR 中启用身份验证,而服务器托管在 ASP.NET WebAPI 中,我正在使用 OAuth Bearer authrnication 并且客户端是 AngularJS。
在客户端,我最初通过 HTTP 标头传递 Bearer 令牌,它与 WebAPI 配合得很好。但是由于 SignalR JavsScript 不支持在其中添加 HTTP 标头connection
(这是因为 WebSocket 不支持指定 HTTP 标头),我需要使用如下代码通过查询字符串传递 Bearer 令牌self.connection.qs = { Bearer: 'xxxxxx' };
问题出在 WebAPI 方面,我的 SignalR 总是返回 401 Unauthorized。
下面是我在 WebAPI 方面所做的。
1,我指定OAuthBearerAuthenticationOptions.Provider
to QueryStringEnabledOAuthBearerAuthenticationProvider
,这是我创建的继承自它的类OAuthBearerAuthenticationProvider
,可以从查询字符串中检索 Bearer 令牌。代码如下。
公共类 QueryStringEnabledOAuthBearerAuthenticationProvider : OAuthBearerAuthenticationProvider { 私有只读字符串_name; 公共 QueryStringEnabledOAuthBearerAuthenticationProvider() :这个(OAuthDefaults.AuthenticationType) { } 公共 QueryStringEnabledOAuthBearerAuthenticationProvider(字符串名称) { _name = 名称; } 公共覆盖任务请求令牌(OAuthRequestTokenContext 上下文) { // 如果可能,尝试从基类(标头)中读取令牌 base.RequestToken(context).Wait(); if (string.IsNullOrWhiteSpace(context.Token)) { // 尝试从查询字符串中读取令牌 var token = context.Request.Query.Get(_name); if (!string.IsNullOrWhiteSpace(token)) { context.Token = 令牌; } } 返回 Task.FromResult(null); } }
并在 WebAPI 启动时将其注册如下。
var options = new OAuthBearerAuthenticationOptions { AuthenticationMode = AuthenticationMode.Active, 身份验证类型 = 身份验证类型, 提供者 = 新的 QueryStringEnabledOAuthBearerAuthenticationProvider(), AccessTokenFormat = _accessTokenFormat, }; config.SuppressDefaultHostAuthentication(); config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType)); app.UseOAuthBearerAuthentication(选项);
2,在 SignalR 部分,我创建了一个授权属性,如下所示。没有任何改变只是用于添加断点。
公共类 BearerAuthorizeAttribute : AuthorizeAttribute { public override bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request) { 返回 base.AuthorizeHubConnection(hubDescriptor, request); } 公共覆盖 bool AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubIncomingInvokerContext, bool applyToMethod) { 返回 base.AuthorizeHubMethodInvocation(hubIncomingInvokerContext, applyToMethod); } }
并在 WebAPI 启动时注册它。
app.Map("/signalr", 地图 => { // 设置 CORS 中间件在 SignalR 之前运行。 // 默认情况下,这将允许所有来源。你可以 // 通过以下方式配置源集和/或 http 动词集 // 提供具有不同策略的 cors 选项。 map.UseCors(CorsOptions.AllowAll); var hubConfiguration = 新的 HubConfiguration { // 您可以通过取消注释下面的行来启用 JSONP。 // JSONP 请求是不安全的,但一些较旧的浏览器(和一些 // IE 版本)需要 JSONP 才能跨域工作 // EnableJSONP = true EnableJavaScriptProxies = false }; // 运行 SignalR 管道。我们没有使用 MapSignalR // 因为这个分支已经在“/signalr”下运行 // 小路。 map.RunSignalR(hubConfiguration); // 要求对所有集线器进行身份验证 var authorizer = new BearerAuthorizeAttribute(); var module = new AuthorizeModule(授权人,授权人); GlobalHost.HubPipeline.AddModule(module); });
我发现,当 SignalR 连接时,我QueryStringEnabledOAuthBearerAuthenticationProvider.RequestToken
被调用并成功检索了 Bearer 令牌。但是,当BearerAuthorizeAttribute.AuthorizeHubConnection
调用 SignalR 时,参数request.User
仍未通过身份验证。所以它返回了 401。
谁能给我一些关于我做错了什么的想法,谢谢。