Eu tenho um aplicativo Web (hospedado no IIS) que fala com um serviço do Windows. O serviço do Windows está usando a API da Web do ASP.Net MVC (auto-hospedado) e, portanto, pode ser comunicado através de http usando JSON. O aplicativo da web está configurado para fazer representação, com a idéia de que o usuário que faz a solicitação para o aplicativo da web seja o usuário que o aplicativo da web usa para fazer a solicitação ao serviço. A estrutura fica assim:
(O usuário destacado em vermelho é o usuário referido nos exemplos abaixo.)
O aplicativo Web faz solicitações para o serviço Windows usando um HttpClient
:
var httpClient = new HttpClient(new HttpClientHandler()
{
UseDefaultCredentials = true
});
httpClient.GetStringAsync("http://localhost/some/endpoint/");
Isso faz a solicitação ao serviço do Windows, mas não passa as credenciais corretamente (o serviço relata o usuário como IIS APPPOOL\ASP.NET 4.0
). Não é isso que eu quero que aconteça .
Se eu alterar o código acima para usar um WebClient
, as credenciais do usuário serão passadas corretamente:
WebClient c = new WebClient
{
UseDefaultCredentials = true
};
c.DownloadStringAsync(new Uri("http://localhost/some/endpoint/"));
Com o código acima, o serviço relata o usuário como o usuário que fez a solicitação para o aplicativo Web.
O que estou fazendo de errado com a HttpClient
implementação que está fazendo com que ela não passe as credenciais corretamente (ou é um bug com o HttpClient
)?
A razão pela qual desejo usar o HttpClient
é que ele possui uma API assíncrona que funciona bem com Task
s, enquanto a WebClient
API assíncrona do s precisa ser manipulada com eventos.
fonte
DownloadStringTaskAsync
em .Net 4.5, que também pode ser usado com async / awaitHttpClient
não possui umSetCredentials()
método. Você pode me indicar o que você quer dizer?new HttpClient(new HttpClientHandler() { AllowAutoRedirect = true, UseDefaultCredentials = true }
em um servidor da web acessado por um usuário autenticado pelo Windows, e o site foi autenticado para outro recurso remoto depois disso (não seria autenticado sem o sinalizador definido).Respostas:
Eu também estava tendo o mesmo problema. Desenvolvi uma solução síncrona graças à pesquisa realizada por @tpeczek no seguinte artigo da SO: Não foi possível autenticar no serviço ASP.NET Web Api com HttpClient
Minha solução usa a
WebClient
, que, como você observou corretamente, passa as credenciais sem problemas. O motivoHttpClient
não funciona é porque a segurança do Windows desabilita a capacidade de criar novos threads em uma conta representada (consulte o artigo SO acima.)HttpClient
Cria novos threads por meio do Task Factory, causando o erro.WebClient
por outro lado, é executado de forma síncrona no mesmo encadeamento, ignorando a regra e encaminhando suas credenciais.Embora o código funcione, a desvantagem é que ele não funcionará de forma assíncrona.
Nota: Requer o pacote NuGet: Newtonsoft.Json, que é o mesmo serializador JSON que a WebAPI usa.
fonte
Você pode configurar
HttpClient
para passar credenciais automaticamente assim:fonte
O que você está tentando fazer é fazer com que o NTLM encaminhe a identidade para o próximo servidor, o que não pode ser feito - ele só pode fazer a representação, o que apenas lhe dá acesso aos recursos locais. Não permitirá que você cruze os limites de uma máquina. A autenticação Kerberos oferece suporte à delegação (o que você precisa) usando tickets, e o ticket pode ser encaminhado quando todos os servidores e aplicativos da cadeia estiverem configurados corretamente e o Kerberos estiver configurado corretamente no domínio. Portanto, em resumo, você precisa mudar do NTLM para o Kerberos.
Para saber mais sobre as opções de autenticação do Windows disponíveis para você e como elas funcionam, comece em: http://msdn.microsoft.com/en-us/library/ff647076.aspx
fonte
WebClient
? É isso que eu não entendo - se não é possível, por que está fazendo isso?WebClient
pode transmitir as credenciais NTLM, mas oHttpClient
não pode. Eu posso conseguir isso usando a representação do ASP.Net sozinha e sem ter que usar o Kerberos ou armazenar nomes de usuário / senhas. No entanto, isso só funciona comWebClient
.OK, obrigado por todos os colaboradores acima. Estou usando o .NET 4.6 e também tivemos o mesmo problema. Passei um tempo depurando
System.Net.Http
, especificamente oHttpClientHandler
, e encontrei o seguinte:Então, depois de avaliar que o
ExecutionContext.IsFlowSuppressed()
culpado pode ter sido o culpado, envolvi nosso código de representação da seguinte maneira:O código dentro de
SafeCaptureIdenity
(não meu erro de ortografia), pegaWindowsIdentity.Current()
qual é a nossa identidade representada. Isso está sendo percebido porque agora estamos suprimindo o fluxo. Devido ao uso / descarte, isso é redefinido após a chamada.Agora parece funcionar para nós, ufa!
fonte
using (System.Threading.ExecutionContext.SuppressFlow())
e o problema foi resolvido para mim!Em .NET Core, eu consegui obter uma
System.Net.Http.HttpClient
comUseDefaultCredentials = true
a passar por credenciais do Windows do usuário autenticado para um serviço de back-end usandoWindowsIdentity.RunImpersonated
.fonte
Funcionou para mim depois de configurar um usuário com acesso à Internet no serviço Windows.
No meu código:
fonte
Ok, então peguei o código Joshoun e o tornei genérico. Não tenho certeza se devo implementar o padrão singleton na classe SynchronousPost. Talvez alguém com mais conhecimento possa ajudar.
Implementação
// Presumo que você tenha seu próprio tipo concreto. No meu caso, eu estou usando o código primeiro com uma classe chamada FileCategoryClasse genérica aqui. Você pode passar qualquer tipo
Minhas aulas de API são assim, se você estiver curioso
Estou usando o ninject e o padrão de repo com a unidade de trabalho. De qualquer forma, a classe genérica acima realmente ajuda.
fonte