HttpClient调用Windows-Authenication ApiController方法…但没有WindowsIdentity出现

当api-controller使用windows-authentication时,我的api控制器是否有办法获得启动api控制器调用的帐户的IIdentity?

我的“castController.User.Identity”是(类型)WindowsIdentity。 但它是“空的”。 空,原样:IsAuthenticated = false,以及一个空的UserName。 它不是空的,它是“空的”。

我的“WebTier”是一个运行自定义AppPool的IIS应用程序,运行自定义AppPool的IIdentity类似于“mydomain \ myServiceAccount”。 我正在尝试将“castController.User.Identity.Name”值作为此服务帐户。

(我想这可能是任何能够使用有效的Windows帐户连接到我的WebApiTier的客户端,但我提到这个以防万一它可能会抛出一个奇怪的猴子扳手)

我的“WebTier”(Mvc Application)有这样的方法:

你会注意到我使用UseDefaultCredentials的两种方法。 (阿卡,我一直试图解决这个问题)

private async Task ExecuteProxy(string url) { HttpClientHandler handler = new HttpClientHandler() { UseDefaultCredentials = true }; handler.PreAuthenticate = true; WebRequestHandler webRequestHandler = new WebRequestHandler(); webRequestHandler.UseDefaultCredentials = true; webRequestHandler.AllowPipelining = true; webRequestHandler.AuthenticationLevel = System.Net.Security.AuthenticationLevel.MutualAuthRequired; webRequestHandler.ImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Identification; using (var client = new HttpClient(handler)) /* i've tried webRequestHandler too */ { Uri destinationUri = new Uri("http://localhost/MyVirtualDirectory/api/mycontroller/mymethod"); this.Request.RequestUri = destinationUri; return await client.SendAsync(this.Request); } } 

“WebApiTier”安装程序。

web.config中

      

“WebApiTier”代码

 public MyController : ApiController { [ActionName("MyMethod")] [MyCustomAuthorization] public IEnumerable MyMethod() { return new string[] { "value1", "value2" }; } } public class MyCustomAuthorizationAttribute : System.Web.Http.AuthorizeAttribute { private string CurrentActionName { get; set; } public override void OnAuthorization(HttpActionContext actionContext) { this.CurrentActionName = actionContext.ActionDescriptor.ActionName; base.OnAuthorization(actionContext); } protected override bool IsAuthorized(HttpActionContext actionContext) { var test1 = System.Threading.Thread.CurrentPrincipal; /* the above is "empty" */ ////string userName = actionContext.RequestContext.Principal;/* Web API v2 */ string userName = string.Empty; ApiController castController = actionContext.ControllerContext.Controller as ApiController; if (null != castController) { userName = castController.User.Identity.Name; /* the above is "empty" */ } return true; } } 

}

再次。 我不是在做“双跳”(我在几个地方读过)。
两个层都在同一个域(和本地开发,它们在同一台机器上)….

有趣的是,我已经读过这篇文章( 如何让HttpClient与请求一起传递凭据? )并且“问题”报告确实是我希望我的工作方式。 (?!?!)。

对于开发,“WebApiTier”在完整的IIS下运行。 对于“WebTier”,我在IIS-Express和全functionIIS下尝试过。

我还使用以下代码运行了一个控制台应用程序:

控制台应用

  IEnumerable returnItems = null; HttpClientHandler handler = new HttpClientHandler() { UseDefaultCredentials = true }; handler.PreAuthenticate = true; WebRequestHandler webRequestHandler = new WebRequestHandler(); webRequestHandler.UseDefaultCredentials = true; webRequestHandler.AllowPipelining = true; webRequestHandler.AuthenticationLevel = System.Net.Security.AuthenticationLevel.MutualAuthRequired; webRequestHandler.ImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Identification; HttpClient client = new HttpClient(handler); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); string serviceUrl = "http://localhost/MyVirtualDirectory/api/mycontroller/mymethod"; HttpResponseMessage response = client.GetAsync(new Uri(serviceUrl)).Result; var temp1 = (response.ToString()); var temp2 = (response.Content.ReadAsStringAsync().Result); if (response.IsSuccessStatusCode) { Task<IEnumerable> wrap = response.Content.ReadAsAsync<IEnumerable>(); if (null != wrap) { returnItems = wrap.Result; } else { throw new ArgumentNullException("Task<IEnumerable>.Result was null. This was not expected."); } } else { throw new HttpRequestException(response.ReasonPhrase + " " + response.RequestMessage); } 

与其他代码的结果相同。 一个“空”的Windows身份。

我也经历了这个

http://www.iis.net/configreference/system.webserver/security/authentication/windowsauthentication

就像一个健全检查。

好。 我想出了这个问题。 感谢这篇文章。

如何在asp.net中识别impersonate =“true”时获取Windows用户名?

//开始引用//

使用应用程序中的并在IIS中启用匿名访问,您将看到以下结果:

 System.Environment.UserName: Computer Name Page.User.Identity.Name: Blank System.Security.Principal.WindowsIdentity.GetCurrent().Name: Computer Name 

//结束报价

因此,我还将包括一个完整的答案…….以显示问题和一些可能需要调整的设置。

去下载这个迷你示例。

https://code.msdn.microsoft.com/ASP-NET-Web-API-Tutorial-8d2588b1

这将为您提供一个名为ProductsApp(ProductsApp.csproj)的快速“WebApiTier”。

如果你想自己做….只需创建一个WebApi控制器……返回一些产品。

 public class ProductsController : ApiController { Product[] products = new Product[] { new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 }, new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M }, new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M } }; [IdentityWhiteListAuthorization] public IEnumerable GetAllProducts() { return products; } } 

打开上面的.sln。

添加一个名为“WebApiIdentityPoc.Domain.csproj”的新“类库”csproj。

在此库中创建一个新类。

 namespace WebApiIdentityPoc.Domain { public class Product { public int Id { get; set; } public string Name { get; set; } public string Category { get; set; } public decimal Price { get; set; } } } 

删除(或注释掉)

\ ProductsApp \型号\ Product.cs

将ProductsApp中的(项目)引用添加到WebApiIdentityPoc.Domain。

修复名称空间问题

\ ProductsApp \ \控制器ProductsController.cs

 //using ProductsApp.Models; using WebApiIdentityPoc.Domain; namespace ProductsApp.Controllers { public class ProductsController : ApiController { 

(您基本上将“Product”对象移动到另一个库,以便Server和Client可以共享同一个对象。)

你应该能够在这一点上进行编译。

……….

向解决方案添加新的“控制台应用程序”项目。

WebApiIdentityPoc.ConsoleOne.csproj

使用Nuget将“Newtonsoft.Json”引用/库添加到WebApiIdentityPoc.ConsoleOne.csproj。

使用右键单击/添加引用在csproj中的“/ References”文件夹中添加引用(Framework或Extensions)

 System.Net.Http System.Net.Http.Formatting System.Net.Http.WebRequest (this one is may not be needed) 

添加项目引用到WebApiIdentityPoc.Domain。

在控制台应用程序的“Program.cs”中,粘贴此代码:………….

 namespace WebApiIdentityPoc.ConsoleOne { using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Security.Principal; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; using WebApiIdentityPoc.Domain; public class Program { private static readonly string WebApiExampleUrl = "http://localhost:47503/api/Products/GetAllProducts"; /* check ProductsApp.csproj properties, "Web" tab, "IIS Express" settings if there is an issue */ public static void Main(string[] args) { try { System.Security.Principal.WindowsIdentity ident = System.Security.Principal.WindowsIdentity.GetCurrent(); if (null != ident) { Console.WriteLine("Will the Identity '{0}' Show up in IdentityWhiteListAuthorizationAttribute ???", ident.Name); } RunHttpClientExample(); RunWebClientExample(); RunWebClientWicExample(); } catch (Exception ex) { System.Text.StringBuilder sb = new System.Text.StringBuilder(); Exception exc = ex; while (null != exc) { sb.Append(exc.GetType().Name + System.Environment.NewLine); sb.Append(exc.Message + System.Environment.NewLine); exc = exc.InnerException; } Console.WriteLine(sb.ToString()); } Console.WriteLine("Press ENTER to exit"); Console.ReadLine(); } private static void RunWebClientExample() { /* some articles said that HttpClient could not pass over the credentials because of async operations, these were some "experiments" using the older WebClient. Stick with HttpClient if you can */ WebClient webClient = new WebClient(); webClient.UseDefaultCredentials = true; string serviceUrl = WebApiExampleUrl; string json = webClient.DownloadString(serviceUrl); IEnumerable returnItems = JsonConvert.DeserializeObject>(json); ShowProducts(returnItems); } private static void RunWebClientWicExample() { /* some articles said that HttpClient could not pass over the credentials because of async operations, these were some "experiments" using the older WebClient. Stick with HttpClient if you can */ System.Security.Principal.WindowsIdentity ident = System.Security.Principal.WindowsIdentity.GetCurrent(); WindowsImpersonationContext wic = ident.Impersonate(); try { WebClient webClient = new WebClient(); webClient.UseDefaultCredentials = true; string serviceUrl = WebApiExampleUrl; string json = webClient.DownloadString(serviceUrl); IEnumerable returnItems = JsonConvert.DeserializeObject>(json); ShowProducts(returnItems); } finally { wic.Undo(); } } private static void RunHttpClientExample() { IEnumerable returnItems = null; HttpClientHandler handler = new HttpClientHandler() { UseDefaultCredentials = true, PreAuthenticate = true }; ////////WebRequestHandler webRequestHandler = new WebRequestHandler(); ////////webRequestHandler.UseDefaultCredentials = true; ////////webRequestHandler.AllowPipelining = true; ////////webRequestHandler.AuthenticationLevel = System.Net.Security.AuthenticationLevel.MutualAuthRequired; ////////webRequestHandler.ImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Identification; using (HttpClient client = new HttpClient(handler)) { client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); string serviceUrl = WebApiExampleUrl; HttpResponseMessage response = client.GetAsync(new Uri(serviceUrl)).Result; var temp1 = response.ToString(); var temp2 = response.Content.ReadAsStringAsync().Result; if (response.IsSuccessStatusCode) { Task> wrap = response.Content.ReadAsAsync>(); if (null != wrap) { returnItems = wrap.Result; } else { throw new ArgumentNullException("Task>.Result was null. This was not expected."); } } else { throw new HttpRequestException(response.ReasonPhrase + " " + response.RequestMessage); } } ShowProducts(returnItems); } private static void ShowProducts(IEnumerable prods) { if (null != prods) { foreach (Product p in prods) { Console.WriteLine("{0}, {1}, {2}, {3}", p.Id, p.Name, p.Price, p.Category); } Console.WriteLine(string.Empty); } } } } 

您应该能够编译并运行并在控制台应用程序中看到一些产品显示。

…..

在“ProductsApp.csproj”中,添加一个新文件夹。

/ WebApiExtensions /

在此文件夹下,添加一个新文件:

IdentityWhiteListAuthorizationAttribute.cs

粘贴此代码:

 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Http; using System.Web.Http.Controllers; namespace ProductsApp.WebApiExtensions { public class IdentityWhiteListAuthorizationAttribute : System.Web.Http.AuthorizeAttribute { public IdentityWhiteListAuthorizationAttribute() { } private string CurrentActionName { get; set; } public override void OnAuthorization(HttpActionContext actionContext) { this.CurrentActionName = actionContext.ActionDescriptor.ActionName; base.OnAuthorization(actionContext); } protected override bool IsAuthorized(HttpActionContext actionContext) { var test1 = System.Threading.Thread.CurrentPrincipal; var test2 = System.Security.Principal.WindowsIdentity.GetCurrent(); ////string userName = actionContext.RequestContext.Principal.Name;/* Web API v2 */ string dingDingDingUserName = string.Empty; ApiController castController = actionContext.ControllerContext.Controller as ApiController; if (null != castController) { dingDingDingUserName = castController.User.Identity.Name; } string status = string.Empty; if (string.IsNullOrEmpty(dingDingDingUserName)) { status = "Not Good. No dingDingDingUserName"; } else { status = "Finally!"; } return true; } } } 

使用此属性装饰webapimethod。

  [IdentityWhiteListAuthorization] public IEnumerable GetAllProducts() { return products; } 

(您必须解析命名空间)。

此时,您应该能够编译….并运行。

但是dingDingDingUserName将是string.Empty。 (跨越这篇文章的原始问题)。

好..

在解决方案资源管理器中单击(左键单击一次)ProductsApp.csproj。

查看属性选项卡。 (这不是“右键单击/属性:::当您只需左键单击ProductsApp.csproj时,这是显示的属性(默认位于VS的右下角)。

你会看到几个设置,但有两个有趣:

 Anonymous Authentication | Enabled Windows Authentication | Enabled 

(注意,以上是这些设置在VS GUI中的显示方式。它们在.csproj文件中显示如下)

  enabled enabled 

如果你设置

 Anonymous Authentication | Disabled 

(在.csproj中显示如下:

 disabled enabled 

瞧! 应显示“dingDingDingName”值。

我上面的链接..指向匿名认证 – 启用问题。

但是这里有一个很长的例子来展示关于HttpClient的直接影响……

我一路上学到了一个警告。

如果你不能改变

 Anonymous Authentication Enabled/Disabled Windows Authentication Enabled/Disabled 

设置,然后您需要调整“主设置”。

在IIS Express中,这将位于如下文件中:

C:\用户\ MyUserName输入\文档\ IISExpress \设置\对ApplicationHost.config

“主设置”需要允许覆盖本地设置。

  

身份validation本身需要在主级别打开。

           

(完整的IIS将具有类似的设置

C:\ WINDOWS \ SYSTEM32 \ INETSRV \设置\的applicationHost.config

底线:

HttpClient可以通过运行HttpClient代码的进程的WindowsIdentity发送….使用HttpClientHandler AND如果为WindowsAuthentication设置了WebApiTier并且关闭了匿名身份validation。

好。 我希望将来帮助某人。