我有一个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中使用的自定义身份验证?
提前Thanx
因此,轻微的逻辑错误:
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的构造函数,因为我没有您所有的类。上面的例子只是概念的证明。