【问题标题】:SignalR authentication failed when passing "Bearer" through query string通过查询字符串传递“承载”时,SignalR 身份验证失败
【发布时间】: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 委托。
  • 我已经在这里回答了这个问题stackoverflow.com/questions/26657296/…

标签: angularjs asp.net-web-api signalr signalr.client bearer-token


【解决方案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/…,但是那里显示的验证码坏了,无法发帖。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-17
  • 2022-01-18
  • 2017-05-02
  • 1970-01-01
  • 2021-01-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多