gpt4 book ai didi

c# - HttpClient 调用 Windows 身份验证 Api Controller 方法...但没有 WindowsIdentity 出现

转载 作者:太空宇宙 更新时间:2023-11-03 13:02:41 26 4
gpt4 key购买 nike

当 api-controller 使用 windows-authentication 时,我的 api Controller 是否有办法获取发起对 api Controller 的调用的帐户的 IIdentity ?

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

我的“WebTier”是一个使用自定义 AppPool 运行的 IIS 应用程序,运行自定义 AppPool 的 IIdentity 类似于“mydomain\myServiceAccount”。
我试图让“castController.User.Identity.Name”值成为这个服务帐户。

(我猜它可能是任何能够使用有效 Windows 帐户连接到我的 WebApiTier 的客户端,但我提到这一点以防万一它可能会抛出一个奇怪的事件 Spanner )

我的“WebTier”(Mvc 应用程序)有这个方法:

您会注意到我使用 UseDefaultCredentials 的两种方式。 (阿卡,我一直试图弄清楚这一点)

    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”设置。

网络配置
  <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;
}
}

}

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

有趣的是,我读过这篇文章( How to get HttpClient to pass credentials along with the request? )并且“问题”报告说我希望我的工作方式完全正确。 (?!?!)。

对于开发,“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

就像一个健全的检查。

最佳答案

行。我弄清楚了这个问题。感谢这篇文章。

How to get Windows user name when identity impersonate="true" in 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 Controller ......返回一些产品。
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。

添加一个名为“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\Models\Product.cs

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

修复命名空间问题

\ProductsApp\Controllers\ProductsController.cs
//using ProductsApp.Models;
using WebApiIdentityPoc.Domain;

namespace ProductsApp.Controllers
{
public class ProductsController : ApiController
{

(您基本上是将“产品”对象移动到另一个库,以便服务器和客户端可以共享同一个对象。)

此时您应该能够编译。

…………

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

WebApiIdentityPoc.ConsoleOne.csproj

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

添加引用(框架或扩展使用右键单击/在 csproj 中的“/References 文件夹中添加引用”)
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<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.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<Product> GetAllProducts()
{
return products;
}

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

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

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

行..

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

查看属性选项卡。 (这不是“右键单击/属性::: 这是显示的属性(默认在 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:\Users\MyUserName\Documents\IISExpress\config\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 匿名身份验证已关闭。

行。我希望这对将来的某人有所帮助。

关于c# - HttpClient 调用 Windows 身份验证 Api Controller 方法...但没有 WindowsIdentity 出现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31887865/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com