Передать IPrincipal из MVC в 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 здесь просто статический класс для хранения вошедших в систему пользователей
Итак, все в моем приложении 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?
Спасибо заранее
1 ответ
Итак, небольшая логическая ошибка:
BaseController.OnAuthorization
срабатывает только когда выполняется контроллер. Когда поступает запрос SignalR, этот метод никогда не будет вызываться для этого запроса.
Таким образом, способ обойти это - переместить код из контроллера в более глобальную область видимости. Например, вы можете использовать Global.asax.cs
и добавь это, Likeo:
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;
}
В качестве альтернативы, вместо Global.asax, я уверен, что вы можете добавить его в конвейер OWIN после аутентификации пользователя. Тем не менее, кто-то еще должен будет предоставить точный пример.
РЕДАКТИРОВАТЬ: просто чтобы уточнить, я изменил конструктор для вашего CustomIdentity, так как у меня не было всех ваших классов. Приведенные выше примеры являются просто доказательством понятий.