Авторизация в SignalR 2.0

У меня есть веб-сервер с проверкой подлинности с помощью форм и еще один сервер, на котором размещены концентраторы 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);
    }
}

Нам нужно установить IPrincipal, связанный с SignalR.


person UglyDuckling2k    schedule 28.11.2013    source источник


Ответы (3)


Если я не ошибаюсь, вы пытаетесь извлечь информацию о вошедшем в систему пользователе из контекста. Если это правильно, этого можно просто добиться, выполнив следующие действия:

  1. Добавьте атрибут [Authorize] в свой хаб-класс.
  2. Затем используйте Context.User.Identity, чтобы получить идентификатор пользователя.

Поскольку вы используете постоянное соединение, вам нужно будет позаботиться о процессе авторизации. Перейдите по этой ссылке, и вы сможете настроить код предоставляется там в соответствии с вашими потребностями.

Чтобы изменить идентификатор запроса, вы должны добавить 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
                }
            }
        }
    }

Надеюсь это поможет.

person Shashank Chaturvedi    schedule 03.01.2014
comment
А без этого атрибута? Атрибут не работает на PersistentConnection :( - person vtortola; 04.01.2014
comment
Я обновил свой ответ, надеюсь, это решит вашу проблему. - person Shashank Chaturvedi; 04.01.2014
comment
К сожалению, IRequest.User доступен только для чтения, поэтому нет реального способа изменить IPrincipal. Я имею в виду, проблема в том, что нам нужно изменить IPrincipal в SignalR, вот о чем вопрос. Ваше здоровье. - person vtortola; 04.01.2014
comment
Вы упомянули, что у вас есть два сервера, как вы подключаетесь к своему сигнальному концентратору с другого сервера. Было бы хорошо, если бы вы могли вставить код. - person Shashank Chaturvedi; 04.01.2014
comment
Приложение MVC поддерживает дуплексное TCP-соединение с сервером. Это соединение передает всю информацию с сервера на соединения SignalR. Это не связано с вопросом :P - person vtortola; 04.01.2014
comment
Я подозреваю, что в вашем случае проблема заключается в том, как информация попадает в концентратор SignalR. Можете ли вы опубликовать код для вашего класса постоянного соединения. - person Shashank Chaturvedi; 04.01.2014
comment
Я не использую никакой концентратор, я использую только PersistentConnection. - person vtortola; 04.01.2014
comment
Итак, вы можете опубликовать код для своего класса, который наследуется от класса PersistentConnection. - person Shashank Chaturvedi; 04.01.2014
comment
Не могу вставить код в комментарий. Однако в классе PersistentConnection нет места для установки IPrincipal. - person vtortola; 04.01.2014
comment
В ссылке, которой я поделился, вы получаете объект IRequest с идентификатором. Вы можете использовать это, чтобы получить объект Iprincipal, как это уже сделано в коде. - person Shashank Chaturvedi; 04.01.2014
comment
Я не уверен, действительно ли я понимаю, почему вы хотите установить объект Iprincipal в первую очередь. Можете ли вы конкретно указать, чего вы пытаетесь достичь. Я считаю, что Iprincipal нельзя установить из-за проблем с безопасностью. Скорее вам придется кодировать весь процесс, если это именно то, что вам нужно. Вот пример кода: codeproject.com/Tips/574576/ - person Shashank Chaturvedi; 04.01.2014
comment
Пользовательская аутентификация, я хочу установить IPrincipal на свой собственный IPrincpial. Это обычная практика. Thread.CurrentPrincipal, HttpContext.Current.User и HttpContextBase.User доступны для записи, но IRequest.User доступен только для чтения. Это проблема. - person vtortola; 04.01.2014
comment
Я обновил свой ответ на основе предоставленного вами разъяснения. Надеюсь, это решит вашу проблему. - person Shashank Chaturvedi; 04.01.2014
comment
@vtortola, пожалуйста, отметьте ответ как ответ, если он вам помог. - person Shashank Chaturvedi; 05.01.2014

Оказывается, Signal-R не может изменить связанный IPrincipal, потому что SignalR не предназначен для аутентификации, но получает контекст аутентификации от приложения. Таким образом, правильный способ сделать это, как указал @Shashank, - использовать формы или что-то еще, что вы используете в своем приложении, и SignalR получит от него этот контекст.

person vtortola    schedule 08.01.2014

Реализуйте интерфейс IUserIdProvider и добавьте его с помощью

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

Вы можете прочитать больше здесь .

person Gustavo Armenta    schedule 04.12.2013
comment
Этот интерфейс только определяет, как вы получаете UserId из IRequest, но не предоставляет способа установить IPrincipal в любом месте. - person vtortola; 31.12.2013