HttpClient & Windows Auth: вход в систему пользователя пользователя для обслуживания
Я изо всех сил пытаюсь понять и настроить Сервис и Потребитель, где Служба будет работать как пользователь, зарегистрированный в Потребителе.
Мой потребитель - это приложение MVC. Моя служба - это приложение Web Api. Оба работают на отдельных серверах в одном домене. Оба установлены для использования Windows Auth.
Мой потребительский код:
private T GenericGet<T>(string p)
{
T result = default(T);
HttpClientHandler handler = new HttpClientHandler() { PreAuthenticate = true, UseDefaultCredentials = true };
using (HttpClient client = new HttpClient(handler))
{
client.BaseAddress = new Uri(serviceEndPoint);
HttpResponseMessage response = client.GetAsync(p).Result;
if (response.IsSuccessStatusCode)
result = response.Content.ReadAsAsync<T>().Result;
}
return result;
}
В моей службе я вызываю User.Identity.Name
, чтобы получить идентификатор вызывающего абонента, но это всегда возвращается в качестве идентификатора пула приложений для клиентов, а не для входа в систему. Потребительский пул приложений работает как сетевая служба, а сам сервер доверен для делегирования. Итак, как я могу получить зарегистрированный пользователь? Сервисный код:
// GET: /Modules/5/Permissions/
[Authorize]
public ModulePermissionsDTO Get(int ModuleID)
{
Module module= moduleRepository.Find(ModuleID);
if (module== null)
throw new HttpResponseException(HttpStatusCode.NotFound);
// This just shows as the App Pool the MVC consumer is running as (Network Service).
IPrincipal loggedInUser = User;
// Do I need to do something with this instead?
string authHeader = HttpContext.Current.Request.Headers["Authorization"];
ModulePermissionsDTO dto = new ModulePermissionsDTO();
// Construct object here based on User...
return dto;
}
В соответствии с этим question Kerberos требуется, чтобы эта настройка работала, потому что HttpClient запускается в отдельном потоке. Однако это меня смущает, потому что я думал, что запрос отправляет заголовок авторизации, и поэтому служба должна иметь возможность использовать это и извлекать токен пользователя. Во всяком случае, я провел некоторое тестирование с Kerberos, чтобы проверить, что это правильно работает в моем домене, используя демо в "Ситуации 5" здесь, и это работает но мои два приложения по-прежнему не будут правильно передавать зарегистрированного пользователя через.
Итак, что мне нужно сделать, чтобы сделать эту работу? Требуется ли Kerberos или мне нужно что-то сделать в моей службе, чтобы распаковать заголовок авторизации и создать основной объект из токена? Все советы были оценены.
Ответы
Ответ 1
Ключ должен позволить вашему приложению (потребителю) MVC олицетворять вызывающего пользователя и затем синхронно выдавать HTTP-запросы (т.е. не порождать новый поток). Вам не нужно беспокоиться о деталях реализации на низком уровне, таких как NTLM и Kerberos.
Потребитель
Настройте приложение MVC следующим образом:
- Запустить диспетчер IIS
- Выберите веб-приложение MVC
- Дважды нажмите "Аутентификация"
- Включить "олицетворение ASP.NET"
- Включить "Аутентификация Windows
- Отключить другие формы аутентификации (если, возможно, не дайджест, если вам это нужно)
- Откройте файл Web.config в корневом каталоге вашего приложения MVC и убедитесь, что
<authentication mode="Windows" />
Чтобы выполнить запрос HTTP, я рекомендую вам использовать отличную библиотеку RestSharp. Пример:
var client = new RestClient("<your base url here>");
client.Authenticator = new NtlmAuthenticator();
var request = new RestRequest("Modules/5/Permissions", Method.GET);
var response = client.Execute<ModulePermissionsDTO>(request);
Сервис
Настройте службу веб-API так:
- Запустить диспетчер IIS
- Выберите службу веб-API
- Дважды нажмите "Аутентификация"
- Отключить "олицетворение ASP.NET".
- Включить "Аутентификация Windows
- Если только подмножество методов веб-API требует аутентификации пользователей, оставьте "Анонимная аутентификация" включенной.
- Откройте файл Web.config в корневой папке службы веб-API и убедитесь, что
<authentication mode="Windows" />
Я вижу, что вы уже украсили свой метод с атрибутом [Authorize]
, который должен инициировать вызов проверки подлинности (HTTP 401) при обращении к этому методу. Теперь вы сможете получить доступ к идентификатору вашего конечного пользователя с помощью свойства User.Identity
вашего класса ApiController.
Ответ 2
Ключевой проблемой с двойным переходом является делегирование учетных данных пользователя во второй вызов. Я хочу немного рассказать об этом. C1 = клиентский браузер, S1 = Первый сервер, S2 = Второй сервер.
Предположим, что наша полная проверка подлинности окна поддержки системы. Когда пользователь получает доступ к S1 из браузера, его учетные данные окна по умолчанию передаются на сервер S1, но когда S1 выполняет вызов S2, по умолчанию он не передает учетные данные для S2.
Разрешение:
- Мы должны включить проверку подлинности/олицетворение окна на обеих машинах.
- Нам нужно включить делегирование между сервером, чтобы S1 мог доверять S2 и передал учетные данные S2.
Вы можете найти полезную информацию по ссылкам ниже:
http://blogs.msdn.com/b/farukcelik/archive/2008/01/02/how-to-set-up-a-kerberos-authentication-scenario-with-sql-server-linked-servers.aspx
https://sqlbadboy.wordpress.com/2013/10/11/the-kerberos-double-hop-problem/
Ответ 3
Если вы пытаетесь получить доступ к сервису, который размещен на проверке подлинности Windows, выполните следующие действия.
var request = new RestRequest(Method.POST);
Если вы хотите использовать учетные данные по умолчанию для приложений, которые должны иметь доступ к серверу размещенных сервисов
request.UseDefaultCredentials = true;
или пользователя ниже, чтобы передать учетные данные вручную
request.Credentials = new NetworkCredential("Username", "Password", "Domain");