通过查询字符串传递“承载”时,SignalR 身份验证失败

Posted

技术标签:

【中文标题】通过查询字符串传递“承载”时,SignalR 身份验证失败【英文标题】:SignalR authentication failed when passing "Bearer" through query string 【发布时间】:2014-07-15 01:56:12 【问题描述】:

我想在 SignalR 中启用身份验证,而服务器托管在 ASP.NET WebAPI 中,我使用 OAuth Bearer 身份验证并且客户端是 AngularJS。

在客户端,我最初通过 HTTP 标头传递 Bearer 令牌,它与 WebAPI 配合得很好。但由于 SignalR JavsScript 不支持在 connection 中添加 HTTP 标头(这是因为 WebSocket 不支持指定 HTTP 标头),我需要使用 self.connection.qs = Bearer: 'xxxxxx' ; 之类的代码通过查询字符串传递 Bearer 令牌

问题出在 WebAPI 端,我的 SignalR 总是返回 401 Unauthorized。

以下是我在 WebAPI 方面所做的。

1,我将OAuthBearerAuthenticationOptions.Provider指定为QueryStringEnabledOAuthBearerAuthenticationProvider,这是我创建的继承自OAuthBearerAuthenticationProvider的类,可以从查询字符串中检索承载令牌。代码如下。

公共类 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 令牌。但是当 SignalR BearerAuthorizeAttribute.AuthorizeHubConnection 被调用时,参数 request.User 仍然没有经过身份验证。所以它返回了 401。

谁能给我一些关于我做错了什么的想法,谢谢。

【问题讨论】:

您不必为了指定自定义 RequestToken 行为而从 OAuthBearerAuthenticationProvider 继承。您可以设置 OAuthBearerAuthenticationProvider 实例的 OnRequestToken 委托。 我已经在这里回答了这个问题***.com/questions/26657296/… 【参考方案1】:

我正在使用标题,这就是我解决它的方法

var authData = localStorageService.get('authorizationData');
var token = authData.token;
$.signalR.ajaxDefaults.headers =  Authorization: "Bearer " + token ;

希望对你有帮助

【讨论】:

设置标头将使用“longPolling”传输。 “webSockets”传输不支持标头。【参考方案2】:

我通过在我的 AuthorizeAttribute 中取消对 Bearer 令牌的查询字符串的保护来解决此问题,并将用户主体设置为新的 ServerRequest。详情请查看http://blog.shaunxu.me/archive/2014/05/27/set-context-user-principal-for-customized-authentication-in-signalr.aspx

这可能不是最好的解决方案,但它确实有效。

【讨论】:

从查询字符串传输令牌是一个安全问题,可以查看、记录等 Shaun Xu,我想评论blog.shaunxu.me/archive/2014/05/27/…,但是那里显示的验证码坏了,无法发帖。

以上是关于通过查询字符串传递“承载”时,SignalR 身份验证失败的主要内容,如果未能解决你的问题,请参考以下文章

.Net SignalR 在还配置了 Cookie 身份验证时使用 JWT 承载身份验证

SignalR accessTokenFactory 不将令牌传递给请求查询字符串

SignalR 和 OpenId 连接

SignalR 和 OpenId 连接

当使用 SelfHost 的 OWIN 承载 SignalR 时,重启 OWIN 后,SignalR 不能正常工作

使用 IdentityServer 承载的 SignalR 不会从 Hub 接收任何 JWTBearerEvents