Context.User.Identity.Name在SignalR 2.X.X中为空。如何修复?

52

这让我发疯了。

我正在使用最新的SignalR版本(2.0.2)。这是我的Hub代码(OnConnected)

        public override Task OnConnected()
        {
            //User is null then Identity and Name too.
            Connections.Add(Context.User.Identity.Name, Context.ConnectionId);
            return base.OnConnected();
        }

这是我的控制器登录方法:

        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
              var user = await UnitOfWork.UserRepository.FindAsync(model.UserName,  model.Password);

                if (user != null)
                {
                    await SignInAsync(user, model.RememberMe);

                    return RedirectToLocal(returnUrl);
                }
            }

            TempData["ErrorMessage"] = Resources.InvalidUserNameOrPassword;

            // If we got this far, something failed, redisplay form
            return RedirectToAction("Index","Home");
        }

我发现一些人在OnDisconnected时遇到了问题,但是我甚至还没有执行到那里。

我正在使用MCV5模板。

您有任何想法出了什么问题吗?


似乎这是一个对于SO来说都很棘手的问题...SignalR的所有者们在哪里呢?我一直在阅读关于版本2.0.3可能会在OnDisconnected时解决类似问题的内容,但已经很长时间没有消息了。像安全这样至关重要的东西却不能正常工作,真是倒霉。 - MRFerocius
由于某些原因,如果计算机时钟不准确(例如,向后一个月),Context.User 将为空。 - Tuomas Hietanen
6个回答

99

我找到了最终解决方案,这是我的OWIN启动类代码:

        public void Configuration(IAppBuilder app)
        {
        app.MapSignalR();

        // Enable the application to use a cookie to store information for the signed i user
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Home/Index")
        });

        // Use a cookie to temporarily store information about a user logging in with a third party login provider
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
        app.UseMicrosoftAccountAuthentication(new MicrosoftProvider().GetAuthenticationOptions());
        app.UseTwitterAuthentication(new TwitterProvider().GetAuthenticationOptions());
        app.UseFacebookAuthentication(new FacebookProvider().GetAuthenticationOptions());
        app.UseGoogleAuthentication(new GoogleProvider().GetAuthenticationOptions());    
    }

在自己做咖啡的时候,我想到“为什么不在身份验证之后映射 SignalR 呢?然后,瞧!现在它按预期工作了。

        public void Configuration(IAppBuilder app)
        {
        // Enable the application to use a cookie to store information for the signed i user
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Home/Index")
        });

        // Use a cookie to temporarily store information about a user logging in with a third party login provider
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
        app.UseMicrosoftAccountAuthentication(new MicrosoftProvider().GetAuthenticationOptions());
        app.UseTwitterAuthentication(new TwitterProvider().GetAuthenticationOptions());
        app.UseFacebookAuthentication(new FacebookProvider().GetAuthenticationOptions());
        app.UseGoogleAuthentication(new GoogleProvider().GetAuthenticationOptions());

        app.MapSignalR();    
    }

5
兄弟,没有提供任何信息自己研究这个太疯狂了。谢谢。根据我的模板,代码应该像这样写: public void Configuration(IAppBuilder app) { // 配置身份验证 ConfigureAuth(app); // 映射SignalR app.MapSignalR(); } - Ronen Festinger
1
@RonenFestinger 我为此苦苦挣扎了10天,没有任何信息,当我找到它时,就像解决费马大定理一样疯狂。疯狂的经历 :| - MRFerocius
这对我没有用。我正在使用OwinContext和OwinContextIdentity。 - ahmadalibaloch
泡一些咖啡给自己喝非常有帮助。 - Timur Lemeshko

5
如果你在同一个项目中使用Web Api和SignalR,你需要先映射SignalR注册Web Api。
将这个改成:
app.UseWebApi(GlobalConfiguration.Configuration);
app.MapSignalR();

变为这样:

app.MapSignalR();
app.UseWebApi(GlobalConfiguration.Configuration);

1
这是一年半前提供的答案。 - MRFerocius
6
@MRFerocius,你提供的答案类似但不同。 你的答案是将app.MapSignalR()移到身份验证下面。我的建议是将其移到app.UseWebApi()上方。同时使用Web Api和SignalR的人可能会发现这个信息很有用,因为它不直观。 - Josh Noe
1
这个对我有用!谢谢! - Chris Woolum
1
谢谢@JoshNoe,我花费了太多的时间在这上面。这解决了我的问题。 - Jonathan

3

请确保在启动app.MapMignalrR()之前调用了认证配置。

我已经做出了更改。

 public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.MapSignalR();
        ConfigureAuth(app);



    }
}

转化为这样

 public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        ConfigureAuth(app);
        app.MapSignalR();


    }
}

抱抱..

2

如果你将/signalr映射为“分支管道”,需要执行以下步骤。确保使用bp.UseCookieAuthentication而不是app

app.Map("/signalr", bp =>
{
   bp.UseCookieAuthentication(new CookieAuthenticationOptions
   {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/store/youRaccount/login")
   });

提示:我故意更改了大小写,所以当我在URL栏中看到youRaccount时,我知道它起作用了:-)


0

我按照上面提到的答案做了一切正确的事情,但仍然没有解决我的问题。

下面的解决方案解决了我的问题。

我使用了http context来获取查询参数中的access_token并解码令牌,从而能够访问所有声明。

public override Task OnConnectedAsync()
{
    var httpContext = Context.GetHttpContext();
    if (httpContext != null)
    {
        var jwtToken = httpContext.Request.Query["access_token"];
        var handler = new JwtSecurityTokenHandler();
        if (!string.IsNullOrEmpty(jwtToken))
        {
            var token = handler.ReadJwtToken(jwtToken);
            var tokenS = token as JwtSecurityToken;

           // replace email with your claim name
            var jti = tokenS.Claims.First(claim => claim.Type == "email").Value;
            if (jti != null && jti != "")
            {
                Groups.AddToGroupAsync(Context.ConnectionId, jti);
            }
        }
    }
    return base.OnConnectedAsync();
}

0

仅限.NET Core SignalR

对于较新的.NET Core SignalR,完整的说明表明在使用WebSockets时,您需要手动从查询字符串中提取accessToken。这很容易被忽略。

https://learn.microsoft.com/en-us/aspnet/core/signalr/authn-and-authz?view=aspnetcore-2.2

基本上,当您调用AddAuthentication()时,您需要添加AddJwtBearer(),然后为OnMessageReceived处理程序设置处理程序。

在上面的链接中搜索“OnMessageReceived”以获取代码。从某种意义上说,这有点棘手,因为您甚至必须自己添加它-但这也是为什么很容易错过的原因。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接