5

我想在 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.Providerto 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。

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

4

2 回答 2

3

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

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

希望能帮助到你

于 2014-10-24T21:25:48.487 回答
0

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

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

于 2014-05-27T07:08:38.400 回答