我有一个使用 Windows 身份验证的 .net core 3.1 Web 应用程序。 Web 应用程序需要以用户身份 向 .net Core 3.1 API 发出请求,并且该 API 还需要以用户身份 调用其他内部网服务。该应用程序和 API 托管在同一台服务器上,并且都使用 Windows 身份验证。
模拟当前 Windows 授权用户发出 API 请求的正确方法是什么?(应用程序可以在不模拟的情况下成功调用 API,但请求将作为应用程序池用户运行。)两个测试
HomeController
中的方法是通过搜索 MS 文档和 SO 示例的日子拼凑而成的,但每个方法都会为版本 FileLoadException
生成一个 System.Net.Http
,该版本没有被 .csproj 文件引用——并且它仅在使用模拟时发生。
// impersonation in the method
public async Task<IActionResult> AskForSomethingWithImpersonationAsync()
{
var apiBase = new Uri(configuration["Api"]);
var response = string.Empty;
var user = (WindowsIdentity)HttpContext.User.Identity;
await WindowsIdentity.RunImpersonated(user.AccessToken, async () =>
{
var credentialsCache = new CredentialCache { { apiBase, "NTLM", CredentialCache.DefaultNetworkCredentials } };
var handler = new HttpClientHandler() { Credentials = credentialsCache };
var httpClient = new HttpClient(handler) { BaseAddress = apiBase, Timeout = new TimeSpan(0, 0, 10) };
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
response = httpClient.GetStringAsync("/api/v2/log").Result;
});
return Content(response);
}
// impersonation middleware
[ServiceFilter(typeof(ImpersonationFilter))]
public async Task<IActionResult> AskForSomethingFilteredAsync()
{
var apiBase = new Uri(configuration["Api"]);
var response = string.Empty;
var user = (WindowsIdentity)HttpContext.User.Identity;
var credentialsCache = new CredentialCache { { apiBase, "NTLM", CredentialCache.DefaultNetworkCredentials } };
var handler = new HttpClientHandler() { Credentials = credentialsCache };
var httpClient = new HttpClient(handler) { BaseAddress = apiBase, Timeout = new TimeSpan(0, 0, 10) };
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
response = await httpClient.GetStringAsync("/api/v2/log");
return Content(response);
}
这里是模拟过滤器中间件:
using Microsoft.AspNetCore.Mvc.Filters;
using System.Security.Principal;
using System.Threading.Tasks;
namespace HBACaller.ActionFilter
{
public class ImpersonationFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(
ActionExecutingContext context,
ActionExecutionDelegate next)
{
var user = (WindowsIdentity)context.HttpContext.User.Identity;
await WindowsIdentity.RunImpersonated(user.AccessToken, async () =>
{
await next();
});
}
}
}
这是我在网络浏览器的网络响应选项卡中看到的错误:
System.IO.FileLoadException:
File name: 'System.Net.Http, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
据我所知,该版本未在任何地方引用。 .csproj 有这个:
<ItemGroup>
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Security.Principal" Version="4.3.0" />
</ItemGroup>
当此代码发布到测试 IIS 服务器而不是通过 Visual Studio 在本地运行时,异常末尾会附加一条消息:
Either a required impersonation level was not provided, or the provided impersonation level is invalid.
如果它有助于查看完整的(失败的)项目,这是回购协议:https://github.com/cestarte/core_impersonate_winauth_user
对于任何试图进行“支持”风格模拟的人,即您以另一个用户身份登录,.net identity 通常在 signinmanager 下有一个名为 PasswordSignInAsync 的功能,但它还有一个很少使用的 SignInAsync,它不需要密码。 Windows Identity / Active Directory 身份验证已死,因为我们已经拥有互联网 25 年了,还因为发生的一切只是你和管理服务器的不可避免的令牌 IT 人员之间的一场愚蠢的战斗,就像任何在 2023 年拥有 AD 的企业一样活在过去,说 IT 人只是在那里为自己的工作安全制造假问题。因此,依赖 AD 身份验证的应用程序在现实世界中永远不会持久。 IT 人员只是更改用户的密码,使您的应用程序失败。