【问题标题】:Pass IPrincipal from MVC to SignalR将 IPrincipal 从 MVC 传递到 SignalR
【发布时间】:2016-02-28 16:29:06
【问题描述】:

我有一个 MVC 应用程序,它使用自定义主体进行基于表单的身份验证。在使用应用程序用户之前必须登录。之后我想使用 SignalR,问题是 Context.User.Identity.Name 总是空字符串。

CustomPrincipal.cs

public class CustomPrincipal : IPrincipal
{
    public CustomPrincipal(IIdentity identity)
    {
        Identity = identity;
    }

    public IIdentity Identity { get; }

    public bool IsInRole(string role)
    {
        return true;
    }
}

CustomIdentity.cs

public class CustomIdentity : IIdentity
{
    public CustomIdentity(EmployeeModel user)
    {
        Name = user.Username;
        Id = user.Id;
    }

    public string AuthenticationType => "Custom";

    public bool IsAuthenticated => !string.IsNullOrEmpty(Name);

    public int Id { get; set; }

    public string Name { get; }
}

BaseController.cs(我从中派生出我所有的 MVC 控制器)

protected override void OnAuthorization(AuthorizationContext context)
{
    if (SessionPersister.User != null && !string.IsNullOrEmpty(SessionPersister.User.Username))
    {
        context.HttpContext.User = new CustomPrincipal(new CustomIdentity(SessionPersister.User));
    }

    base.OnAuthorization(context);
}

这里的SessionPersister只是一个存储登录用户的静态类

所以,我的 MVC 应用程序中的一切都运行良好。当用户登录并且我想向通过 SignalR 登录的另一个用户发送消息时,Identity.User.Name 在我的 Hub 类中是一个空字符串的问题:

public override Task OnConnected()
{
    string name = Context.User.Identity.Name; // it's empty

    return base.OnConnected();
}

有什么方法可以将我的 MVC IPrincipal 传递给 SignalR 或将其配置为使用我在 MVC 中使用的自定义身份验证?

提前感谢

【问题讨论】:

  • 什么版本的 ASP.NET MVC?
  • 我也遇到了同样的问题,有更新吗?

标签: authentication model-view-controller signalr identity iprincipal


【解决方案1】:

所以,有点逻辑错误:

BaseController.OnAuthorization 仅在执行控制器时触发。当 SignalR 请求通过时,该方法将永远为该请求调用。

因此,一种解决方法是将代码从控制器移动到更全局的范围。例如,您可以使用Global.asax.cs 并添加它,如下所示:

    protected void Application_PostAuthenticateRequest( object sender, EventArgs e )
    {
        //do your custom principal setting here.
        this.Context.User = new CustomPrincipal( new CustomIdentity( 10, "test" ) );
    }

然后,在您的中心,您将能够看到如下所示的身份:

    public String Hello(String hello)
    {
        //no need to actually cast if you don't need the non-iidentity properties
        //var identity = (CustomIdentity) this.Context.User.Identity;
        //identity.Id == 10
        //identity.Name == "test"

        return hello;
    }

或者,我相信您可以在用户身份验证后将其放入 OWIN 管道中,而不是 Global.asax。但是,其他人需要提供一个确切的例子。

编辑:为了澄清,我更改了您的 CustomIdentity 的构造函数,因为我没有您的所有类。上面的这个例子只是概念证明。

【讨论】: