【问题标题】:Context.User.Identity.Name is null with SignalR 2.X.X. How to fix it?SignalR 2.X.X 的 Context.User.Identity.Name 为空。如何解决?
【发布时间】:2014-02-25 00:24:34
【问题描述】:

这让我发疯了。

我正在使用最新的 signalR 版本 (2.0.2)。这是我的集线器代码(OnConnected)

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

这是我的Controller的登录方法:

        [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 时解决类似的问题,但是很长一段时间没有消息。像安全性这样对工作至关重要的东西不能正常工作。真倒霉。
  • 由于某种原因,如果计算机时钟的时间不正确(例如一个月前),Context.User 将为空。

标签: asp.net-mvc authentication signalr signalr-hub owin


【解决方案1】:

我找到了最终的解决方案,这是我的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();    
    }

【讨论】:

  • 伙计,在没有提供任何信息的情况下自己动手完成这项工作真是太疯狂了。谢谢。在我的模板中,它必须是这样的: public void Configuration(IAppBuilder app) { ConfigureAuth(app); app.MapSignalR(); }
  • @RonenFestinger 我为此苦苦挣扎了 10 天,没有任何信息,当我发现这就像解决费马大定理一样。疯了:|
  • 这对我不起作用。我正在使用 OwinContext 和 OwinContextIdentity。
  • “给自己煮点咖啡”——对我很有帮助)
【解决方案2】:

如果您在同一个项目中使用 Web Api 和 SignalR,则必须在 注册 Web Api 之前映射 SignalR。

改变这个:

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

到这里:

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

【讨论】:

  • 这是提供了一年半的答案。-
  • @MRFerocius 您提供的答案相似但不同。您的答案是将app.MapSignalR() 移至身份验证下方。我的是将其移到 上方 app.UseWebApi()。同时使用 Web Api 和 SignalR 的人可能会发现此信息很有用,因为它不直观。
  • 这个是为我做的!谢谢!
  • 谢谢@JoshNoe 我花了太多时间在这上面。这解决了我的问题。
【解决方案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();


    }
}

拥抱..

【讨论】:

    【解决方案4】:

    如果您将/signalr 映射为“分支管道”,则需要执行此操作。确保使用bp.UseCookieAuthentication 而不是app

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

    提示:我直接更改了大小写,所以当我在 URL 栏中看到 youRaccount 时,我知道它有效 :-)

    【讨论】:

      【解决方案5】:

      .NET Core SignalR 仅

      对于较新的 .NET Core SignalR,完整说明解释说,在使用 websockets 时,您需要手动从查询字符串中提取 accessToken。这是 很容易错过。

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

      基本上在调用AddAuthentication() 的地方需要添加AddJwtBearer(),然后为OnMessageReceived 处理程序设置一个处理程序。

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

      【讨论】:

        【解决方案6】:

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

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

        我使用 http 上下文 从查询参数中获取 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();
        }
        

        【讨论】:

          猜你喜欢
          • 2018-06-25
          • 1970-01-01
          • 1970-01-01
          • 2021-09-18
          • 1970-01-01
          • 1970-01-01
          • 2019-02-18
          • 2013-01-12
          • 2020-11-09
          相关资源
          最近更新 更多