我有一个常规的ASP.Net Core网站,用户可以使用Windows身份验证来访问该网站,以确定哪些用户可以访问哪些页面。
为了为用户呈现页面,站点需要调用一系列Web服务来获取各种数据。这些Web服务不使用Windows身份验证。相反,它们需要用户的JWT令牌。
因此,我们的WebSite需要将用户的Windows令牌交换为JWT令牌。我们有一个特殊的ExchangeToken Web服务,该服务使用Windows身份验证接受请求,并返回用户的JWT令牌。
当我希望WebSite调用此ExchangeToken Web服务时,困难就来了。我需要使用模拟来调用它,以便可以重新获得用户的JWT令牌。但是,似乎无法将HttpClient与模拟一起使用。
起初,我计划在WebSite中这样做:
但是,根据what I've read,为每个调用重新创建HTTP客户端是不好的做法,而我should be使用HttpClientFactory instead。
但是,我不知道这种方法如何与模拟一起使用。
我尝试过:
但是,发生的是,尽管有模拟,对<< all >>的TokenExchange服务的调用还是使用same Windows凭据进行的-Windows凭据是碰巧首先访问该网站的用户的凭据。 AFAIK,这源于Windows身份验证的工作方式-在您使用HttpClient时first会执行令牌交换,此后,对该客户端的所有调用都使用相同的令牌。一种选择是为每个用户创建一个单独的客户端...但是我有大约7,000个用户,所以这似乎有点过分!
另一种选择是信任该WebSite代表用户使用其自己的帐户来获取令牌。问题在于它需要信任WebSite。如果它被攻击者攻破,那么我就无法阻止攻击者为任意用户窃取JWT令牌。而通过模拟,攻击者仍然无法在没有首先获得其Windows令牌的情况下获得用户的JWT令牌。
所以,有没有一种方法可以一起模拟+ IHttpClientFactory?还是有更好的方法来解决所有这些问题?
((如果很重要,我公司拥有自己的Windows服务器-我们还不在云中)
为了演示第二种方法的问题,我做了一个测试应用程序。它实际上并没有使用HttpClientFactory,但确实演示了该问题。
我从一个网站开始,该网站只返回拨打电话的用户:
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class WhoController : ControllerBase
{
[HttpGet]
public ActionResult<string> Get()
{
return User.Identity.Name;
}
}
我的客户代码如下:
private void CallClient(HttpClient httpClient, string username, string password)
{
LogonUser(username, "MYDOMAIN", password, 2, 0, out IntPtr token);
var accessTokenHandle = new SafeAccessTokenHandle(token);
WindowsIdentity.RunImpersonated(
accessTokenHandle,
() =>
{
string result = httpClient.GetStringAsync("http://MyServer/api/who").Result;
Console.WriteLine(result);
});
}
我的测试代码像这样调用它:
public void Test()
{
var httpClient = new HttpClient(new HttpClientHandler { UseDefaultCredentials = true });
CallClient(httpClient, "User1", "Password1");
CallClient(httpClient, "User2", "Password2");
}
如上所述,我将以下内容写入控制台:
User1
User1
我想要的是:
User1
User2
我有一个常规的ASP.Net Core网站,用户可以使用Windows身份验证来访问该网站,以确定哪些用户可以访问哪些页面。为了为用户呈现页面,站点需要调用...