J'ai une application Web (hébergée dans IIS) qui communique avec un service Windows. Le service Windows utilise l'API Web ASP.Net MVC (auto-hébergée) et peut donc être communiqué via http à l'aide de JSON. L'application Web est configurée pour effectuer une usurpation d'identité, l'idée étant que l'utilisateur qui fait la demande à l'application Web doit être l'utilisateur que l'application Web utilise pour faire la demande au service. La structure ressemble à ceci:
(L'utilisateur surligné en rouge est l'utilisateur auquel il est fait référence dans les exemples ci-dessous.)
L'application Web envoie des demandes au service Windows à l'aide d'un HttpClient
:
var httpClient = new HttpClient(new HttpClientHandler()
{
UseDefaultCredentials = true
});
httpClient.GetStringAsync("http://localhost/some/endpoint/");
Cela fait la demande au service Windows, mais ne transmet pas correctement les informations d'identification (le service signale l'utilisateur comme IIS APPPOOL\ASP.NET 4.0
). Ce n'est pas ce que je souhaite .
Si je change le code ci-dessus pour utiliser à la WebClient
place, les informations d'identification de l'utilisateur sont transmises correctement:
WebClient c = new WebClient
{
UseDefaultCredentials = true
};
c.DownloadStringAsync(new Uri("http://localhost/some/endpoint/"));
Avec le code ci-dessus, le service signale l'utilisateur comme l'utilisateur qui a fait la demande à l'application Web.
Qu'est-ce que je fais mal avec l' HttpClient
implémentation qui fait qu'elle ne transmet pas correctement les informations d'identification (ou est-ce un bogue avec le HttpClient
)?
La raison pour laquelle je veux utiliser l ' HttpClient
est qu'il a une API asynchrone qui fonctionne bien avec Task
s, alors que l WebClient
' API asyc doit être gérée avec des événements.
la source
DownloadStringTaskAsync
dans .Net 4.5, qui peut également être utilisé avec async / awaitHttpClient
n'a pas deSetCredentials()
méthode. Pouvez-vous m'indiquer ce que vous voulez dire?new HttpClient(new HttpClientHandler() { AllowAutoRedirect = true, UseDefaultCredentials = true }
sur un serveur Web accédé par un utilisateur authentifié par Windows, et le site Web s'est authentifié pour une autre ressource distante après cela (ne s'authentifierait pas sans le jeu d'indicateurs).Réponses:
J'avais aussi ce même problème. J'ai développé une solution synchrone grâce à la recherche effectuée par @tpeczek dans l'article SO suivant: Impossible de s'authentifier auprès du service Web Api ASP.NET avec HttpClient
Ma solution utilise un
WebClient
, qui, comme vous l'avez correctement noté, transmet les informations d'identification sans problème. La raisonHttpClient
ne fonctionne pas parce que la sécurité Windows désactive la possibilité de créer de nouveaux threads sous un compte usurpé (voir l'article SO ci-dessus.)HttpClient
Crée de nouveaux threads via Task Factory, provoquant ainsi l'erreur.WebClient
d'autre part, s'exécute de manière synchrone sur le même thread, contournant ainsi la règle et transmettant ses informations d'identification.Bien que le code fonctionne, l'inconvénient est qu'il ne fonctionnera pas de manière asynchrone.
Remarque: nécessite le package NuGet: Newtonsoft.Json, qui est le même que le sérialiseur JSON que WebAPI utilise.
la source
Vous pouvez configurer
HttpClient
pour transmettre automatiquement les informations d'identification comme ceci:la source
Ce que vous essayez de faire, c'est demander à NTLM de transmettre l'identité au serveur suivant, ce qu'il ne peut pas faire - il ne peut faire que l'emprunt d'identité qui vous donne uniquement accès aux ressources locales. Cela ne vous permettra pas de franchir les limites d'une machine. L'authentification Kerberos prend en charge la délégation (dont vous avez besoin) à l'aide de tickets, et le ticket peut être transféré lorsque tous les serveurs et applications de la chaîne sont correctement configurés et que Kerberos est correctement configuré sur le domaine. Donc, en bref, vous devez passer de NTLM à Kerberos.
Pour en savoir plus sur les options d'authentification Windows disponibles et leur fonctionnement, accédez à: http://msdn.microsoft.com/en-us/library/ff647076.aspx
la source
WebClient
? C'est ce que je ne comprends pas - si ce n'est pas possible, comment se fait-il qu'il le fasse?WebClient
peut transmettre les informations d'identification NTLM, mais leHttpClient
ne peut pas. Je peux y parvenir en utilisant uniquement l'emprunt d'identité ASP.Net, sans avoir à utiliser Kerberos ou à stocker les noms d'utilisateur / mots de passe. Cela ne fonctionne cependant qu'avecWebClient
.OK, merci à tous les contributeurs ci-dessus. J'utilise .NET 4.6 et nous avons également eu le même problème. J'ai passé du temps à déboguer
System.Net.Http
, en particulier leHttpClientHandler
, et j'ai trouvé ce qui suit:Donc, après avoir évalué que cela
ExecutionContext.IsFlowSuppressed()
aurait pu être le coupable, j'ai enveloppé notre code d'usurpation d'identité comme suit:Le code à l'intérieur de
SafeCaptureIdenity
(pas ma faute d'orthographe), saisitWindowsIdentity.Current()
qui est notre identité usurpée. Cela est repris parce que nous supprimons maintenant le flux. En raison de l'utilisation / de l'élimination, ceci est réinitialisé après l'appel.Cela semble maintenant fonctionner pour nous, ouf!
la source
using (System.Threading.ExecutionContext.SuppressFlow())
et le problème a été résolu pour moi!Dans .NET Core, j'ai réussi à obtenir un
System.Net.Http.HttpClient
withUseDefaultCredentials = true
pour transmettre les informations d'identification Windows de l'utilisateur authentifié à un service principal en utilisantWindowsIdentity.RunImpersonated
.la source
Cela a fonctionné pour moi après avoir configuré un utilisateur avec un accès Internet dans le service Windows.
Dans mon code:
la source
Ok donc j'ai pris le code Joshoun et l'ai rendu générique. Je ne suis pas sûr de devoir implémenter le modèle singleton sur la classe SynchronousPost. Peut-être que quelqu'un de plus compétent peut vous aider.
la mise en oeuvre
// Je suppose que vous avez votre propre type concret. Dans mon cas, j'utilise d'abord le code avec une classe appelée FileCategoryClasse générique ici. Vous pouvez passer n'importe quel type
Mes classes d'API ressemblent à ceci, si vous êtes curieux
J'utilise ninject et repo pattern avec unité de travail. Quoi qu'il en soit, la classe générique ci-dessus aide vraiment.
la source