模拟当前用户使用WindowsImpersonationContext访问网络驱动器
我需要从Web App访问远程驱动器。该驱动器无法访问ASP.NET进程,因此我想模拟当前用户的请求。模拟当前用户使用WindowsImpersonationContext访问网络驱动器
我看到了一些使用WindowsImpersonationContext的基本示例,并尝试了以下内容。
WindowsImpersonationContext impersonationContext = null;
try
{
impersonationContext = ((WindowsIdentity)User.Identity).Impersonate();
file.SaveAs(filePath);
}
finally
{
if (impersonationContext != null)
{
impersonationContext.Undo();
}
}
我仍然收到拒绝访问异常。
我读过一些关于LogonUser
的内容,但据我所知,需要用户名和密码才能从中获取凭证。我不打算作为一个不同的特定用户登录,只是当前用户(谁应该有权访问文件存储),所以我不认为我实际上需要LogonUser
API。
有没有人有任何想法我失踪?上面的代码应该工作吗?
我还注意到,包括
<identity impersonate="true" />
不工作,但包括
<identity impersonate="true" userName="myName" password="myPassword" />
web.config
让我进去。我见过几个人问为什么这是问题,但我没有看到任何解释。我想知道它是否与我的问题相关。
您可能会遇到模拟与授权问题。当您模拟用户时,可以以该用户的身份访问本地资源,但不能访问远程资源。通过授权,您也可以访问远程资源。请尝试以下操作:
- 确保Windows身份验证在IIS中启用,并且匿名身份验证被禁用(匿名身份验证需要的其他身份验证机制优先)
- 在你的web.config启用
<authentication mode="Windows" />
确保ASP.NET处理Windows身份验证(这应该只适用于经典管道模式)。 -
<identity impersonate="true" />
应该就够了。
您可能需要做的另一件事是确保运行AppPool的帐户可以像代理一样行事。
我已经完成了所有设置,并且不起作用。你能否解释一下你最后一点的含义,*确保运行AppPool的账户可以像委托人一样行事*?我不确定你的意思,你有链接吗?谢谢 – fearofawhackplanet 2010-10-11 08:01:25
我写了一个辅助类,做它:
public static class ImpersonationUtils
{
private const int SW_SHOW = 5;
private const int TOKEN_QUERY = 0x0008;
private const int TOKEN_DUPLICATE = 0x0002;
private const int TOKEN_ASSIGN_PRIMARY = 0x0001;
private const int STARTF_USESHOWWINDOW = 0x00000001;
private const int STARTF_FORCEONFEEDBACK = 0x00000040;
private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
private const int TOKEN_IMPERSONATE = 0x0004;
private const int TOKEN_QUERY_SOURCE = 0x0010;
private const int TOKEN_ADJUST_PRIVILEGES = 0x0020;
private const int TOKEN_ADJUST_GROUPS = 0x0040;
private const int TOKEN_ADJUST_DEFAULT = 0x0080;
private const int TOKEN_ADJUST_SESSIONID = 0x0100;
private const int STANDARD_RIGHTS_REQUIRED = 0x000F0000;
private const int TOKEN_ALL_ACCESS =
STANDARD_RIGHTS_REQUIRED |
TOKEN_ASSIGN_PRIMARY |
TOKEN_DUPLICATE |
TOKEN_IMPERSONATE |
TOKEN_QUERY |
TOKEN_QUERY_SOURCE |
TOKEN_ADJUST_PRIVILEGES |
TOKEN_ADJUST_GROUPS |
TOKEN_ADJUST_DEFAULT |
TOKEN_ADJUST_SESSIONID;
[StructLayout(LayoutKind.Sequential)]
private struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[StructLayout(LayoutKind.Sequential)]
private struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[StructLayout(LayoutKind.Sequential)]
private struct STARTUPINFO
{
public int cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public int dwX;
public int dwY;
public int dwXSize;
public int dwYSize;
public int dwXCountChars;
public int dwYCountChars;
public int dwFillAttribute;
public int dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
private enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous,
SecurityIdentification,
SecurityImpersonation,
SecurityDelegation
}
private enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation
}
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool CreateProcessAsUser(
IntPtr hToken,
string lpApplicationName,
string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandles,
int dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool DuplicateTokenEx(
IntPtr hExistingToken,
int dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
int ImpersonationLevel,
int dwTokenType,
ref IntPtr phNewToken);
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool OpenProcessToken(
IntPtr ProcessHandle,
int DesiredAccess,
ref IntPtr TokenHandle);
[DllImport("userenv.dll", SetLastError = true)]
private static extern bool CreateEnvironmentBlock(
ref IntPtr lpEnvironment,
IntPtr hToken,
bool bInherit);
[DllImport("userenv.dll", SetLastError = true)]
private static extern bool DestroyEnvironmentBlock(
IntPtr lpEnvironment);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(
IntPtr hObject);
private static void LaunchProcessAsUser(string cmdLine, IntPtr token, IntPtr envBlock, int sessionId)
{
var pi = new PROCESS_INFORMATION();
var saProcess = new SECURITY_ATTRIBUTES();
var saThread = new SECURITY_ATTRIBUTES();
saProcess.nLength = Marshal.SizeOf(saProcess);
saThread.nLength = Marshal.SizeOf(saThread);
var si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = @"WinSta0\Default";
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_FORCEONFEEDBACK;
si.wShowWindow = SW_SHOW;
if (!CreateProcessAsUser(
token,
null,
cmdLine,
ref saProcess,
ref saThread,
false,
CREATE_UNICODE_ENVIRONMENT,
envBlock,
null,
ref si,
out pi))
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "CreateProcessAsUser failed");
}
}
private static IDisposable Impersonate(IntPtr token)
{
var identity = new WindowsIdentity(token);
return identity.Impersonate();
}
private static IntPtr GetPrimaryToken(Process process)
{
var token = IntPtr.Zero;
var primaryToken = IntPtr.Zero;
if (OpenProcessToken(process.Handle, TOKEN_DUPLICATE, ref token))
{
var sa = new SECURITY_ATTRIBUTES();
sa.nLength = Marshal.SizeOf(sa);
if (!DuplicateTokenEx(
token,
TOKEN_ALL_ACCESS,
ref sa,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
(int)TOKEN_TYPE.TokenPrimary,
ref primaryToken))
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "DuplicateTokenEx failed");
}
CloseHandle(token);
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "OpenProcessToken failed");
}
return primaryToken;
}
private static IntPtr GetEnvironmentBlock(IntPtr token)
{
var envBlock = IntPtr.Zero;
if (!CreateEnvironmentBlock(ref envBlock, token, false))
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "CreateEnvironmentBlock failed");
}
return envBlock;
}
public static void LaunchAsCurrentUser(string cmdLine)
{
var process = Process.GetProcessesByName("explorer").FirstOrDefault();
if (process != null)
{
var token = GetPrimaryToken(process);
if (token != IntPtr.Zero)
{
var envBlock = GetEnvironmentBlock(token);
if (envBlock != IntPtr.Zero)
{
LaunchProcessAsUser(cmdLine, token, envBlock, process.SessionId);
if (!DestroyEnvironmentBlock(envBlock))
{
throw new Win32Exception(Marshal.GetLastWin32Error(), "DestroyEnvironmentBlock failed");
}
}
CloseHandle(token);
}
}
}
public static IDisposable ImpersonateCurrentUser()
{
var process = Process.GetProcessesByName("explorer").FirstOrDefault();
if (process != null)
{
var token = GetPrimaryToken(process);
if (token != IntPtr.Zero)
{
return Impersonate(token);
}
}
throw new Exception("Could not find explorer.exe");
}
}
您可以使用它像:
ImpersonationUtils.LaunchAsCurrentUser("notepad");
using (ImpersonationUtils.ImpersonateCurrentUser())
{
}
更多解释和例子,你可以在这里找到:
嗨,我用你的代码Console.WriteLine WindowsIdentity.GetCurrent()。名称在远程计算机上,其中另一个用户登录,使用psexec。它崩溃在行“if(OpenProcessToken(process.Handle,TOKEN_DUPLICATE,ref token))”抛出一个负面的错误代码,我无法找出它的含义。我错过了什么?谢谢。编辑:我在一个域中,其中我的用户和另一台计算机中的用户都是管理员 – Loaderon 2016-08-02 21:56:13
我一直在这个问题上敲打我的头2天!使用Chrome时,每次对Active Directory的调用都会崩溃。你的班级做到了!工程就像一个魅力和易于使用!谢谢!! – Philippe 2017-01-31 03:03:10
网站是否运行匿名或Windows身份? – Viv 2010-10-08 14:00:07
@Vivek:IIS设置为使用Window标识。谢谢 – fearofawhackplanet 2010-10-11 11:18:01