是否有一种方法可以让我的api控制器获得在api控制器使用windows身份验证时发起调用api控制器的帐户的IIdentity ?
我"castController.User。"身份"是(类型)WindowsIdentity。但它是"空的"。空,如:IsAuthenticated = false和空UserName。它不是空的,它是"empty"
我的"WebTier"是一个运行自定义appool的IIS应用程序,而运行自定义appool的IIdentity类似于"mydomainmyServiceAccount"。我试图获得"castController.User.Identity"。
将"Name"值指定为此服务帐户。(我猜它可能是任何客户端谁能够连接到我的WebApiTier与一个有效的windows帐户,但我提到这只是以防它可能扔一个奇怪的扳手)
我的"WebTier"(Mvc应用程序)有这个方法:
你会注意到我使用UseDefaultCredentials的两种方式。(Aka,我一直试图弄清楚这一点)
private async Task<HttpResponseMessage> 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
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<authentication mode="Windows" />
"WebApiTier"代码
public MyController : ApiController
{
[ActionName("MyMethod")]
[MyCustomAuthorization]
public IEnumerable<string> 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和完整的IIS下尝试过。
我还运行了一个控制台应用程序,代码如下:
控制台应用程序
IEnumerable<string> 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<string>> wrap = response.Content.ReadAsAsync<IEnumerable<string>>();
if (null != wrap)
{
returnItems = wrap.Result;
}
else
{
throw new ArgumentNullException("Task<IEnumerable<string>>.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只是为了检查一下。
好的。我找到了问题所在。感谢这篇文章。
如何在身份冒充时获取Windows用户名="true"在asp.net ?
//开始引用//
在应用程序中使用<authentication mode="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控制器…返回一些product。
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<Product> GetAllProducts()
{
return products;
}
}
打开上面的。sln.
添加一个新的"类库" csproj名为"WebApiIdentityPoc.Domain.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"对象移动到另一个库中,这样服务器和客户端就可以共享同一个对象。)
此时应该可以编译了。
..........
在解决方案中添加一个新的"Console Application"项目。
WebApiIdentityPoc.ConsoleOne.csproj
使用Nuget添加"Newtonsoft"。WebApiIdentityPoc.ConsoleOne.csproj.
添加引用(框架或扩展使用右键单击/添加引用在"/references"文件夹在csproj)
System.Net.Http
System.Net.Http.Formatting
System.Net.Http.WebRequest (this one is may not be needed)
为WebApiIdentityPoc.Domain添加一个项目引用。
在控制台App的"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<Product> returnItems = JsonConvert.DeserializeObject<IEnumerable<Product>>(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<Product> returnItems = JsonConvert.DeserializeObject<IEnumerable<Product>>(json);
ShowProducts(returnItems);
}
finally
{
wic.Undo();
}
}
private static void RunHttpClientExample()
{
IEnumerable<Product> 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<IEnumerable<Product>> wrap = response.Content.ReadAsAsync<IEnumerable<Product>>();
if (null != wrap)
{
returnItems = wrap.Result;
}
else
{
throw new ArgumentNullException("Task<IEnumerable<Product>>.Result was null. This was not expected.");
}
}
else
{
throw new HttpRequestException(response.ReasonPhrase + " " + response.RequestMessage);
}
}
ShowProducts(returnItems);
}
private static void ShowProducts(IEnumerable<Product> 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
。
/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<Product> GetAllProducts()
{
return products;
}
(您必须解析名称空间)。
此时,您应该能够编译....和运行。但是dingDingDingUserName将是string.Empty。(这篇文章的原始问题)
好吧. .
点击(左键点击一次)ProductsApp。
查看属性选项卡。(这不是"右键单击/属性:::这是显示的属性(默认会在VS的右下角),当你简单地左键单击ProductsApp.csproj.
您将看到几个设置,但有两个感兴趣:
Anonymous Authentication | Enabled
Windows Authentication | Enabled
(注意,以上是这些设置在VS GUI中显示的方式。它们在.csproj文件中显示如下)
<IISExpressAnonymousAuthentication>enabled</IISExpressAnonymousAuthentication>
<IISExpressWindowsAuthentication>enabled</IISExpressWindowsAuthentication>
如果你设置
Anonymous Authentication | Disabled
(在.csproj中显示如下:
)<IISExpressAnonymousAuthentication>disabled</IISExpressAnonymousAuthentication>
<IISExpressWindowsAuthentication>enabled</IISExpressWindowsAuthentication>
)
瞧!应该显示"dingDingDingName"的值。
我上面的链接…指向启用匿名身份验证的问题。
但是这里有一个很长的例子来展示直接影响…关于HttpClient.
这是我学到的另一个警告。
如果你不能改变
Anonymous Authentication Enabled/Disabled
Windows Authentication Enabled/Disabled
设置,然后你需要调整"主设置"。
在IIS Express中,它将位于如下文件中:
C: IISExpress config 文件上的用户名都用户 dangillmor applicationhost.config
"主设置"需要允许覆盖本地设置。
<sectionGroup name="security">
<section name="anonymousAuthentication" overrideModeDefault="Allow" />
<!-- Other Stuff -->
<section name="windowsAuthentication" overrideModeDefault="Allow" />
</sectionGroup>
身份验证本身需要在主级别上打开。
<security>
<authentication>
<anonymousAuthentication enabled="true" userName="" />
<windowsAuthentication enabled="true">
<providers>
<add value="Negotiate" />
<add value="NTLM" />
</providers>
</windowsAuthentication>
</authentication>
(完整的IIS将在
中有类似的设置)C: Windows System32系统 inetsrv config applicationHost.config
)
底线:
HttpClient可以发送运行HttpClient代码....的进程的WindowsIdentity使用HttpClientHandler 和如果WebApiTier设置为WindowsAuthentication 和匿名认证关闭。
Ok。我希望这对将来的人有所帮助。