【问题标题】:Authorization in SignalR 2.0SignalR 2.0 中的授权
【发布时间】:2014-01-08 18:32:03
【问题描述】:

我有一个带有表单身份验证的 Web 服务器和另一个托管 SignalR 集线器的服务器。使用表单身份验证 cookie,我想使用下面的代码提取当前用户。这可以使用 HttpModule,但在使用 SignalR 时,不能使用 HttpModule。

还有其他方法可以归档我想做的事情吗?

public class AuthorizationHubModule : HubPipelineModule
{
    public AuthorizationHubModule()
    {
    }

    protected override bool OnBeforeConnect(IHub hub)
    {
        var cookies = hub.Context.Request.Cookies;
        if (cookies.ContainsKey(".ASPXAUTH") == true)
        {
            // Get the user, populate the Thread.CurrentUser...
            Cookie cookie = cookies[".ASPXAUTH"];

            if (cookie != null)
            {
                FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);

                GenericIdentity identity = new GenericIdentity(ticket.Name);
                GenericPrincipal principal = new GenericPrincipal(identity, new string[0]);

                // Cannot do this because User is readonly (this is possible in a normal HttpModule)
                //hub.Context.User = principal;
            }
        }

        return base.OnBeforeConnect(hub);
    }
}

我们要做的是设置与 SignalR 关联的 IPrincipal。

【问题讨论】:

    标签: asp.net authorization signalr signalr-hub


    【解决方案1】:

    如果我没记错的话,您正在尝试从上下文中提取登录用户的用户信息。如果这是正确的,这可以通过执行以下操作来简单地实现:

    1. 将 [Authorize] 属性添加到您的中心类。
    2. 然后使用 Context.User.Identity 获取用户身份。

    由于您使用的是持久连接,因此您需要注意授权过程。参考this link,您可以根据需要调整那里提供的代码。

    要更改请求的身份,您必须将 FormsAuthentication_OnAuthenticate 添加到您的 global.asax。这是我为我的应用程序编写的示例代码:

    protected void FormsAuthentication_OnAuthenticate(Object sender, FormsAuthenticationEventArgs e)
        {
            if (FormsAuthentication.CookiesSupported == true)
            {
                if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
                {
                    try
                    {
                        string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
    
                        //Let us set the Pricipal with our user specific details
                        e.User = new System.Security.Principal.GenericPrincipal(
                          new System.Security.Principal.GenericIdentity(username, "Forms"), _user.GetUserRoles(username));                        
                    }
                    catch (Exception)
                    {
                        //somehting went wrong
                    }
                }
            }
        }
    

    希望这会有所帮助。

    【讨论】:

    • 没有那个属性?该属性不适用于 PersistentConnection :(
    • 我已经更新了我的答案,希望能解决你的问题。
    • 不幸的是 IRequest.User 是只读的,因此没有实际的方法来更改 IPrincipal。我的意思是,问题是我们需要更改 SignalR 中的 IPrincipal,这就是问题所在。干杯。
    • 您提到您有两台服务器,如何从另一台服务器连接到您的信号器集线器。能贴一下代码就好了。
    • MVC 应用程序持有与服务器的双工 TCP 连接。该连接将所有信息从服务器中继到 SignalR 连接。这与问题无关:P
    【解决方案2】:

    事实证明,Signal-R 无法修改关联的 IPrincipal,因为 SignalR 并非旨在进行身份验证,但它从应用程序获取身份验证上下文。因此,正如@Shashank 指出的那样,正确的做法是使用 Forms 或您在应用程序中使用的任何东西,SignalR 将从中获取此上下文。

    【讨论】:

      【解决方案3】:

      实现接口IUserIdProvider并使用添加

      GlobalHost.Configuration.Resolver.Register(typeof(IUserIdProvider), () => provider.Object);
      

      您可以阅读更多here

      【讨论】:

      • 该接口只定义了如何从 IRequest 中获取 UserId,但没有提供在任何地方设置 IPrincipal 的方法。
      猜你喜欢
      • 2014-01-06
      • 1970-01-01
      • 2021-08-31
      • 1970-01-01
      • 2012-05-31
      • 2014-05-24
      • 2014-03-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多