Windows Azure: веб-приложение на нескольких экземплярах, аутентификация?

Существующее веб-приложение, которое я хочу перенести в Windows Azure Cloud, аутентифицирует пользователей следующим образом в событии (post) Authenticaterequest:

IPrincipal current = Thread.CurrentPrincipal;
if (current != null && ((IClaimsIdentity)current.Identity).Claims.Count > 0)
{
    IPrincipal result =  AuthManager.CreateGenericPrincipal(current.Identity);
    HttpContext.Current.User = result;
    Thread.CurrentPrincipal = result;
}

Метод CreateGenericPrincipal выполняет поиск ролей в XML-файле для идентификатора утверждений и создает новый GenericPrincipal с этими ролями. Страницы, которым требуется аутентификация, просто выполняют

IPrincipal p = Thread.CurrentPrincipal;
p.IsInRole("rolesFromXml");

Это отлично работает с одним экземпляром веб-роли, поскольку нет большой разницы с обычным хостингом IIS. Но будет ли он работать с 2, 3 или 5 экземплярами? Балансировщик нагрузки Azure не является «липким», пользователи могут быть перенаправлены на другой экземпляр во время использования приложения. Не знаю, подходит ли Thread.CurrentPrincipal.

Здесь я использую удостоверение на основе утверждений. Когда пользователь впервые входит на страницу, он попадает в службу токенов безопасности. До сих пор это случается только один раз. Было бы неприятно, если бы такое случалось несколько раз при использовании нескольких экземпляров ..

Спасибо!


person ceran    schedule 25.10.2011    source источник


Ответы (2)


Обычно происходит то, что вас перенаправляют только один раз, происходит танец перенаправления (пассивное перенаправление), и вы получаете токен. Токен обычно кэшируется в файле cookie в зашифрованном формате. Таким образом, последующие запросы не танцуют перенаправления.

Проблема здесь в том, что, поскольку файл cookie зашифрован, все серверы в веб-ферме должны иметь ключ шифрования для дешифрования. Из коробки вы столкнетесь с проблемами с WIF, потому что по умолчанию он использует DPAPI. Этот тип шифрования намеренно различается для разных машин. Это ломается в облаке.

Что вам нужно сделать, так это загрузить сертификат службы как часть вашего развертывания и изменить способ шифрования файлов cookie на что-то удобное для веб-фермы. Вот магический код:

private void OnServiceConfigurationCreated(object sender, 
    ServiceConfigurationCreatedEventArgs e)
{
    var sessionTransforms =
        new List<CookieTransform>(
            new CookieTransform[] 
            {
                new DeflateCookieTransform(), 
                new RsaEncryptionCookieTransform(
                  e.ServiceConfiguration.ServiceCertificate),
                new RsaSignatureCookieTransform(
                  e.ServiceConfiguration.ServiceCertificate)  
            });
    var sessionHandler = new 
     SessionSecurityTokenHandler(sessionTransforms.AsReadOnly());
    e.ServiceConfiguration.SecurityTokenHandlers.AddOrReplace(
        sessionHandler);
}

Это настраивает обработчик токенов безопасности для использования шифрования RSA с ключевыми материалами, полученными из установленного сертификата.

В этом примере приложения приведены более подробные сведения и информация, которые иллюстрируют проблему и решение:

http://msdn.microsoft.com/en-us/library/ff966481.aspx

Дополнительное редактирование:

В ASP.NET есть конвейер, в котором настроен WIF. Он перехватывает событие аутентификации, извлекает токен из файла cookie и создает ваш IPrincipal, чтобы последующий код имел его в контексте. Обычно вы не создаете Принципала самостоятельно при использовании STS. Вместо этого, если вам нужно изменить принципала, вы подключаетесь к конвейеру в WIF и вставляете дополнительные утверждения в утверждение «роль» (на самом деле пространство имен URI). Затем WIF будет использовать эти утверждения для создания ClaimsPrincipal, который будет содержать такие вещи, как роли, и все, что просто работает (IsInRole, web.config auth и т. Д.).

Если возможно, лучше всего, чтобы токен содержал роли в качестве утверждений. Однако это гораздо более длинная дискуссия о «нормализации» требований к значимым контекстам. Помните, что утверждения, которые вы получаете от IP-STS, сформулированы сами по себе и могут ничего не значить для вашего приложения. Например, я могу получить утверждение от клиента о том, что он входит в группу Adatum \ Managers. Это совершенно бессмысленно для моего приложения, поэтому я обычно обмениваю этот токен на тот, который понимает мое приложение, и в процессе трансформирую или нормализую утверждения с помощью сопоставлений утверждений (например, Adatum \ Managers -> MyApplicationAdminRole). Служба Windows Azure ACS очень применима, чтобы помочь в этом (нормализовать заявки с разных IP-адресов).

Я бы рекомендовал прочитать об этом книгу Витторио, получите общие шаблоны здесь:

Примечания Эухенио: Добавление к тому, что написал @dunnry, и это все правильно. Правильная точка расширения для расширения вашего утверждения, установленного в проверяющей стороне (вашем веб-приложении), - это использование ClaimsAuthenticationManager. Документация для этого типа находится здесь. на этой странице есть указатели на образцы. В этом классе вы читаете роли из XML-файла и добавляете их в ClaimsIdentity. Остальная часть приложения не будет беспокоиться о претензиях и т. Д. (Особенно, если вы используете роли, как в вашем случае). Конфигурация RSA для шифрования файлов cookie решает проблему балансировщика нагрузки.

person dunnry    schedule 25.10.2011
comment
Вам нужно подключить это событие при запуске приложения. - person RubbleFord; 25.10.2011
comment
@Eugenio Pace, это выглядит многообещающим. Если я не ошибаюсь, я мог бы добавить пользовательскую роль через ClaimsAutneticationManager (новое утверждение (... / претензии / роль, администратор)), а затем просто использовать user.isInRole (администратор)? это действительно было бы очень легко - person ceran; 26.10.2011
comment
@ceran - точно. Просто используйте стандартный ClaimTypes.Role. Фактически, любой API-интерфейс ASP.NET, использующий User.IsInRole, работает (например, [Authorize (Roles = Admin)] в MVC. - person Eugenio Pace; 26.10.2011
comment
Спасибо Евгенио, мне очень помог - person ceran; 26.10.2011

Посмотрите мой пост, я сделал то же самое.

http://therubblecoder.wordpress.com/2011/10/25/wif-and-load-balancing-with-mvc-3/

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

В элементе конфигурации microsoft.identity вам необходимо иметь такой элемент.

<serviceCertificate>
  <certificateReference x509FindType="FindByThumbprint"    findValue="****THUMBPRINT*****" storeLocation="LocalMachine"  storeName="My" />
</serviceCertificate>

Пул приложений также должен будет получить к нему доступ, иначе он не сможет найти сертификат по отпечатку пальца.

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

person RubbleFord    schedule 25.10.2011
comment
Спасибо, я уже видел эту штуку с печеньем в лаборатории WIF. Но я не понимаю всего процесса. Что именно происходит, когда IPrincipal p = Thread.CurrentPrincipal вызывается в другом экземпляре? Мой объект GenericPrincipal (см. Выше), который должен быть CurrentPrincipal, больше не доступен, не так ли? Что именно сейчас происходит? - person ceran; 25.10.2011
comment
@ceran - последующие запросы обычно используют кешированный билет, хранящийся в файле cookie (IPrincipal строится с использованием этого при каждом запросе). Однако есть предостережения для веб-фермы (например, Azure). См. Мой ответ для более подробной информации - person dunnry; 25.10.2011
comment
Хорошо, еще раз спасибо. Я понимаю необходимость шифрования cookie без APAPI, я понимаю, что IPrincipal создается с помощью cookie, но я не могу объединить его. Последний вопрос, забудьте на данный момент WIF и претензии. Когда я делаю это и ничего больше в первом запросе: Thread.CurrentPrincipal = new GenericPrincipal (new identity (), mySuperRoles), поэтому все последующие запросы к другим экземплярам будут создавать принципала с mySuperRoles? (По крайней мере, когда я преобразовал cookie, о котором вы упомянули, конечно). - person ceran; 25.10.2011
comment
Да, я думаю, что вы правы .... Разве вы не можете поместить свои роли в СС, чтобы они передавались обратно в виде требований. Тогда должен работать стандартный материал IsInRole. Я предполагаю, что вы контролируете СС, когда говорю это. - person RubbleFord; 25.10.2011