ASP.NET Core 3.0:如何将现有身份验证转发给另一个请求 - 双跳问题?

ASP.NET Core 3.0: How to forward an existing authentication to another request - double hop problem?

我遇到了以下情况(所有应用程序和服务都在 Windows 上使用 asp.net 核心 3.0):

我有一个在 AppUser 上下文中运行的客户端应用程序。它使用 HttpClient 向在 WebUser 上下文中运行的 WebServiceA 发送请求。 该请求使用 Windows 身份验证。

    var credentialsCache = new CredentialCache { { uri, "Negotiate", CredentialCache.DefaultNetworkCredentials } };
    var handler = new HttpClientHandler { Credentials = credentialsCache };
    var httpClient = new HttpClient(handler);

在 WebServiceA 中,调用被正确接收并经过身份验证: HttpContext.User.Identity.IsAuthenticated 为真,HttpContext.User.Identity.Name 为 AppUser。

为了能够处理请求,WebServiceA 必须向 WebServiceB 发送另一个请求。 此请求还必须作为 AppUser.

进行身份验证

目前我正在使用以下代码创建向 WebServiceB 发出请求的 HttpClient:

    var credentialsCache = new CredentialCache { { uri, "Negotiate", CredentialCache.DefaultNetworkCredentials } };
    HttpClientHandler handler = new HttpClientHandler
    {
        Credentials = credentialsCache,
        UseDefaultCredentials = true
    };
    HttpClient httpClient = new HttpClient(handler);

问题是,调用始终被验证为 WebUser(运行服务的人),而不是 AppUser(发送请求的人)

我认为 DefaultNetworkCredentials 始终是经过身份验证的用户的。

我如何发送(从 WebRequest 中)另一个 WebRequest 到另一个 WebService,该 WebService 已通过提交原始请求的同一用户进行身份验证? 有没有办法将身份验证从一个 WebService 传递到另一个 WebService?

关于 Kerberos 和 AD: WebServiceA 和 WebServiceB 在同一域中的不同服务器上 运行。它们不是托管在 IIS 中,而是托管在 Windows 服务中。

我尝试按照此处所述设置 SPN: https://docs.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.0&tabs=visual-studio

setspn -S HTTP/ServerA.domain domain\WebUser

也试过: setspn -a WebServiceA/WebUser domain\WebUser

但是没有成功。

经过三天的网络研究和尝试,我的头晕了... 如何将 UserCredentials 放入第二个请求中? 还是因为(可能是错误的?)AD 配置 (SPN),WebService 总是默默地获取启动服务的用户的凭据?

感谢每一个提示!

史蒂菲

OP 在评论中接受的答案涉及假冒。根据这个 blog entry 可以在 .Net Core 中使用 WindowsIdentity.RunImpersonated:

// The user to be impersonated
var userToImpersonate = (WindowsIdentity)HttpContext.User.Identity;

// Impersonating the current Windows user [HttpContext.User.Identity]...
var result = await WindowsIdentity.RunImpersonated(
                                 userToImpersonate.AccessToken, async () =>
{
    // This time WindowsIdentity.GetCurrent() will retrieve the impersonated
    // user with its claims...
    var impersonatedUser = WindowsIdentity.GetCurrent().Name;

    // Your business logic code here...  
});