我有一个带有Windows身份验证的.net / c#web应用程序(web api)。该服务托管在我的本地计算机上,IIS 10.应用程序池标识设置给我,当前登录到windows用户。计算机处于活动目录域中。
我想使用帐户访问共享文件,当前登录到应用程序。文件具有适当的权限。出于这个目的,我使用这样的模拟:
if (HttpContext.Current.User.Identity is WindowsIdentity windowsIdentity)
{
using (windowsIdentity.Impersonate())
{
FileStream stream = new FileStream(@"\\server\share\file.ext", FileMode.Open, FileAccess.Read);
}
}
我使用当前的Windows帐户登录,与在应用程序池标识中设置的相同。这适用于托管应用程序的本地计算机上的共享文件。但不适用于位于另一台计算机上的远程共享文件。另一台计算机也在活动目录域中。
从托管计算机我可以使用Windows资源管理器或我的浏览器访问共享文件。此外,如果我没有冒充用户,.net尝试使用应用程序池身份帐户访问共享文件(设置为同一个用户,我),并且本地和远程文件都成功。
它也适用于从advapi32.dll的LogonUser方法获得的模拟身份。但它需要用户密码,我不想从用户请求密码,已经登录到应用程序。
我究竟做错了什么?
更新:如果位于托管计算机上的共享文件,则由Windows生成的登录事件(事件查看器中的安全选项卡)显示正确的用户。如果共享文件位于另一台计算机上,则此计算机上的Windows生成的登录事件将显示匿名用户。所以,帐户不知何故丢失了。
更新2:如果我在IIS上运行站点(如localhost(url中的localhost)),则模拟会起作用。但如果我使用ip或网站名称运行它会停止工作。
更新3:Wireshark显示获取票证(访问共享文件服务器)的请求失败,错误“KRB5KDC_ERR_BADOPTION NT状态:STATUS_NOT_FOUND”。 AD中允许的应用程序池用户委派。在cmd中执行Dir命令时,可以成功检索没有委派的相同票证(对于cifs / fileshareservername)(wireshark显示)。看起来像AD中的问题。
无法确定你所做的事情是否错误,但我可以告诉你我做了一件非常相似的事情。我的.Net站点没有正常的WindowsLogin,所以我不得不做一个额外的跳转,我认为你可以做同样的事情,也许不是最好的答案。
登录时(在我的membershipProvider中)我运行以下代码:
try
{
if (LogonUser(user,domain,password, [AD_LOGIN],
LOGON32_PROVIDER_DEFAULT, ref handle))
{
IntPtr tokenDuplicate = IntPtr.Zero;
if (DuplicateToken(handle, SecurityImpersonation,
ref tokenDuplicate) != 0)
{
// store off duplicate token here
}
}
}
finally
{
if (handle != IntPtr.Zero)
{
CloseHandle(handle);
}
}
然后当你需要冒充时,这样做:
var context = WindowsIdentity.Impersonate(tokenDuplicate);
try
{
// do your file access here
}
finally
{
context.Dispose();
}
我不得不对tokenDuplicate变量做一些有趣的转换。它是一个整数值,但指向存储令牌信息的特定内存地址。只要您登录,它就会保持良好状态。
为什么你不能直接冒充你的身份,不知道。我只知道它对我来说有一个令牌,这是我获取一个可用于模仿的令牌的方法。
它开始为我工作,具有以下设置。
美国;
所有其他魔法都发生在Active目录中: