Skip to main content
 首页 » 编程设计

c#之从具有集成 Windows 身份验证的 MVC 应用程序调用 Web API

2024年02月05日30shihaiming

我有一个 MVC 应用程序和一个关联的 Web API 项目,它们都托管在 IIS 的远程服务器上。它们共享同一个应用程序池。每当我尝试从 MVC 应用程序调用 Web API 时,我都会收到 403 错误,这似乎是由 HttpClientHandler 传递的错误凭据引起的。我有

UseDefaultCredentials = true  

我试过设置

Credentials = CredentialCache.DefaultNetworkCredentials 

但这些都不允许 API 请求通过。

将应用程序池设置为使用我的 AD 用户名/密码允许所有 API 请求通过,并且直接从 Postman 调用 API 会正确返回数据。

我的假设是 IIS AppPool[Pool Name] 在请求中被转发,并且从未传递正确的凭据。无论如何,在不使 API 不安全的情况下是否有解决这个问题的方法(即只有几个域组应该能够访问它)?

我从 MVC 应用程序调用 API 的示例

    public async Task<HttpResponseMessage> CreateIncident(Incident model) 
    { 
        using (var client = new HttpClient(new HttpClientHandler { UseDefaultCredentials = true })) 
        { 
            var newIncident = new StringContent(JsonConvert.SerializeObject(model), Encoding.UTF8, "application/json"); 
            var response = await client.PostAsync(hostUri, newIncident); 
            return response; 
        } 
    } 

请您参考如下方法:

没有更多信息,很难确定,但问题可能是由于您尝试的双跳身份验证所致。

  1. 客户端应用程序(如果是网站,则为浏览器) 验证客户端发送的用户
  2. 服务器的身份验证(MVC 应用程序)
  3. 然后 MVC 应用程序尝试将身份验证传递给 Web 服务

当我需要执行类似的任务时,我无法让 HttpClient 工作。我尝试了这个问题的一些建议解决方案,How to get HttpClient to pass credentials along with the request? .虽然它提供了丰富的信息——具体来说,BlackSpy 的这部分回答解释了原因:

What you are trying to do is get NTLM to forward the identity on to the next server, which it cannot do - it can only do impersonation which only gives you access to local resources.

我最终在 MVC 应用程序中使用 WebClient(需要以 .NET 框架为目标)和类似的东西(在本例中是从 Web API 下载文件):

private async Task GetFileAsync(Identity identity, string serviceAddress, Stream stream) 
{ 
    var windowsIdentity = Identity as WindowsIdentity; 
 
    if (windowsIdentity == null) 
    { 
        throw new InvalidOperationException("Identity not a valid windows identity."); 
    } 
 
    using (windowsIdentity.Impersonate()) 
    { 
        using (var client = new WebClient { UseDefaultCredentials = true }) 
        { 
            var fileData = await client.DownloadDataTaskAsync(serviceAddress); 
            await stream.WriteAsync(fileData, 0, fileData.Length); 
            stream.Seek(0, SeekOrigin.Begin); 
        } 
    } 
} 

虽然针对完整框架的要求阻止了它成为 .NET Core 解决方案,但看起来它是从那时起添加的。

Add WebClient to new System.Net.WebClient contract

This PR ports System.Net.WebClient to corefx. The code is mostly taken from desktop and then cleaned up a bit stylistically. The only major code rewrite was removing hundreds of lines of complicated APM callback-based code and replacing it with a few core async methods. There's still plenty of more cleanup that can be done, but functionally this is sufficient.