将 IPrincipal 从 MVC 传递到 SignalR

Pass IPrincipal from MVC to SignalR

我有一个 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只是一个静态的class用来存储登录用户

因此,我的 MVC 应用程序中的所有内容都运行良好。当用户登录并且我想向通过 SignalR 登录的另一个用户发送消息时,Identity.User.Name 在我的 Hub class:

中是一个空字符串的问题
public override Task OnConnected()
{
    string name = Context.User.Identity.Name; // it's empty

    return base.OnConnected();
}

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

提前致谢

所以,轻微的逻辑错误:

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

因此,一种解决方法是将代码从 Controller 移动到更全局的范围。例如,您可以使用 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 的构造函数,因为我没有您的全部 类。上面的例子只是概念证明。