将ClaimsPrincipal分配/推送到SignalR上下文

时间:2017-12-18 13:38:06

标签: c# asp.net-web-api2 signalr signalr-hub

好的,所以这个肯定会把我推向悬崖的边缘......与SignalR的V1合作相对容易,我现在肯定在挣扎。

问题:"抓住"来自最近通过身份验证的用户Claims并在Hub

中传递/使用

环境

WebAPI使用Basic AuthSSL进行身份验证。验证的逻辑在一个属性内并且工作正常并且已经持续数月,它还在AuthenticateAsync

内生成/构建声明

在我的API Controller中,我抓住了声明:

var idenityInstance = new IdentityInstance(this.User as ClaimsPrincipal);

我周末花了很多时间尝试使用Groups / SSL和Authentication来合并SignalR的V2。

我一般认为ClaimsPrincipal会传递或传递给#34; Context"。

            public void Configuration(IAppBuilder app)
            {
                // Branch the pipeline here for requests that start with "/signalr"
                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
                    };
                    // Run the SignalR pipeline. We're not using MapSignalR
                    // since this branch already runs under the "/signalr"
                    // path.
                    map.RunSignalR(hubConfiguration);
                });

            }

自定义授权属性(从文档中获取)

        protected override bool UserAuthorized(System.Security.Principal.IPrincipal user)
        {
            if (user == null)
            {
                throw new ArgumentNullException("user");
            }

            var principal = user as ClaimsPrincipal;

            if (principal != null)
            {
                Claim authenticated = principal.FindFirst(ClaimTypes.Authentication);
                if (authenticated != null && authenticated.Value == "true")
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

好的,最后一个片段,The Hub(剥离后的)

        public async Task Hello()
        {
            //Temp line for testing under local SSL/Self signed
            ServicePointManager.ServerCertificateValidationCallback
                += (sender, cert, chain, sslPolicyErrors) => true;

            var hubConnection = new HubConnection("https://localhost:44357");


            IHubProxy chatHubProxy = hubConnection.CreateHubProxy("printerHub");



            hubConnection.Start().Wait();
            var c = Context;
            await hubContext.Clients.All.hello("Hello");
        }

问题是当我通过Hub Method Hello(); Context进行调试始终是null时,由于自定义authenticate attribute >

我希望我在这里错过了一些愚蠢的事情,因为它肯定非常令人沮丧。

1 个答案:

答案 0 :(得分:1)

好吧,这比首次预期的要复杂一些,现在解决方案可能不适合“某些”环境,但在这种情况下,解决了问题。

我们始终牢记我们正在处理两个Contexts ...

要重新上限,我WebAPI basic auth超过SSL - 效果非常好,现在的想法是提供一种方法来锁定{{1}并且仅允许访问经过身份验证的用户且超出Hubs的范围。由于basic authWebAPI在两个进程中运行,SignalR的访问权限可以在Hubs管道之外。

要演示的一些代码:

中心:

WebAPI

SignalR自定义身份验证属性

    [HubAuthorizationAttribute]
    [HubName("printerHub")]
    public class PrinterHub : Hub
    {
        private static IHubContext hubContext =
            GlobalHost.ConnectionManager.GetHubContext<PrinterHub>();


        private IdentityInstance _userInstanceContext;
        private User _user;
        public override Task OnConnected()
        {
            //Custom logic to return a User object
            _userInstanceContext = new IdentityInstance(this.Context.User as ClaimsPrincipal);
            _user = _userInstanceContext.Create();
            return base.OnConnected();
        }
        public override Task OnDisconnected(bool stopping)
        {
            return base.OnDisconnected(stopping);
        }
        public async Task JoinPrinterNotifications()
        {
            await hubContext.Groups.Add(Context.ConnectionId, _user.ClientName + ":Printers");
        }
        public async Task PrintQueues(IEnumerable<QueuedPrintItem> items)
        {
            await hubContext.Clients.Group(_user.ClientName + ":Printers").notify(items);
        }