HttpClient 和 Windows 身份验证:将消费者的登录用户传递给服务

本文关键字:用户 登录 服务 消费者 Windows 身份验证 HttpClient | 更新日期: 2023-09-27 18:34:58

我正在努力理解和设置一个服务和消费者,其中服务将在用户登录消费者时运行。

我的消费者是 MVC 应用程序。我的服务是一个 Web API 应用程序。两者都在同一域中的不同服务器上运行。两者都设置为使用 Windows 身份验证。

我的消费者代码是:

private T GenericGet<T>(string p)
    {
        T result = default(T);
        HttpClientHandler handler = new HttpClientHandler() { PreAuthenticate = true, UseDefaultCredentials = true };
        using (HttpClient client = new HttpClient(handler))
        {
            client.BaseAddress = new Uri(serviceEndPoint);
            HttpResponseMessage response = client.GetAsync(p).Result;
            if (response.IsSuccessStatusCode)
                result = response.Content.ReadAsAsync<T>().Result;
        }
        return result;
    }

在我的服务中,我调用User.Identity.Name以获取调用方 ID,但这始终作为使用者应用程序池 ID 返回,而不是登录用户。使用者应用程序池作为网络服务运行,服务器本身受信任以进行委派。那么如何获取登录用户呢?服务代码:

    // GET: /Modules/5/Permissions/
    [Authorize]
    public ModulePermissionsDTO Get(int ModuleID)
    {
        Module module= moduleRepository.Find(ModuleID);
        if (module== null)
            throw new HttpResponseException(HttpStatusCode.NotFound);
        // This just shows as the App Pool the MVC consumer is running as (Network Service).
        IPrincipal loggedInUser = User;
        // Do I need to do something with this instead?
        string authHeader = HttpContext.Current.Request.Headers["Authorization"];
        ModulePermissionsDTO dto = new ModulePermissionsDTO();
        // Construct object here based on User...
        return dto;
    }

根据这个问题,Kerberos 需要使此设置正常工作,因为 HttpClient 在单独的线程中运行。但是这让我感到困惑,因为我认为请求发送了一个授权标头,因此服务应该能够使用它并检索用户令牌。无论如何,我已经使用 Kerberos 进行了一些测试,以使用此处"情况 5"中的演示检查这是否在我的域上正确工作,这有效,但我的两个应用程序仍然无法正确传递登录用户。

那么我需要做什么才能完成这项工作呢?是否需要 Kerberos,或者我是否需要在我的服务中执行某些操作来解压缩授权标头并从令牌创建主体对象?所有的建议都表示赞赏。

HttpClient 和 Windows 身份验证:将消费者的登录用户传递给服务

关键是让您的 MVC 应用程序(使用者(模拟调用用户,然后同步发出 HTTP 请求(即不生成新线程(。您不必关注低级实现细节,例如 NTLM 与 Kerberos。

消费者

按如下方式配置 MVC 应用程序:

  1. 启动 IIS 管理器
  2. 选择您的 MVC Web 应用程序
  3. 双击"身份验证">
  4. 启用"ASP.NET 模拟">
  5. 启用"窗口身份验证">
  6. 禁用其他形式的身份验证(除非如果需要,可能会使用摘要(
  7. 在 MVC 应用程序的根目录中打开 Web.config 文件,并确保<authentication mode="Windows" />

要发出HTTP请求,我建议您使用优秀的RestSharp库。例:

var client = new RestClient("<your base url here>");
client.Authenticator = new NtlmAuthenticator();
var request = new RestRequest("Modules/5/Permissions", Method.GET);
var response = client.Execute<ModulePermissionsDTO>(request);

服务

按如下所示配置 Web API 服务:

  1. 启动 IIS 管理器
  2. 选择您的 Web API 服务
  3. 双击"身份验证">
  4. 禁用"ASP.NET 模拟"。
  5. 启用"窗口身份验证">
  6. 如果只有一部分 Web API 方法需要对用户进行身份验证,请保持启用"匿名身份验证"。
  7. 在 Web API 服务的根目录中打开 Web.config 文件,并确保<authentication mode="Windows" />

我可以看到您已经使用 [Authorize] 属性装饰了您的方法,该属性应在访问该方法时触发身份验证质询 (HTTP 401(。现在,您应该能够通过 ApiController 类的 User.Identity 属性访问最终用户的标识。

如果您尝试访问托管在Windows身份验证上的服务,请执行以下操作。

var request = new RestRequest(Method.POST);

如果要使用必须在托管服务服务器上具有访问权限的应用程序默认凭据

request.UseDefaultCredentials = true;

下面的用户手动传递凭据

request.Credentials = new NetworkCredential("Username", "Password", "Domain");

双跃点的关键问题是将用户凭据委派给第二个调用。我想对此进行一些详细说明。C1 = 客户端浏览器,S1 = 第一台服务器,S2 = 第二台服务器。

假设我们完整的系统支持窗口身份验证。当用户从浏览器访问 S1 时,其默认窗口凭据传递到服务器 S1,但当 S1 调用 S2 时,默认情况下它不会将凭据传递给 S2。

分辨率:

  1. 我们必须在两台计算机上启用窗口身份验证/模拟。
  2. 我们需要在服务器之间启用委派,以便 S1 可以信任 S2 并将凭据传递给 S2。

您可以在以下链接中找到一些有用的详细信息:http://blogs.msdn.com/b/farukcelik/archive/2008/01/02/how-to-set-up-a-kerberos-authentication-scenario-with-sql-server-linked-servers.aspx

https://sqlbadboy.wordpress.com/2013/10/11/the-kerberos-double-hop-problem/