2010-10-08 57 views
3

我需要从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

让我进去。我见过几个人问为什么这是问题,但我没有看到任何解释。我想知道它是否与我的问题相关。

+0

网站是否运行匿名或Windows身份? – Viv 2010-10-08 14:00:07

+0

@Vivek:IIS设置为使用Window标识。谢谢 – fearofawhackplanet 2010-10-11 11:18:01

回答

3

您可能会遇到模拟与授权问题。当您模拟用户时,可以以该用户的身份访问本地资源,但不能访问远程资源。通过授权,您也可以访问远程资源。请尝试以下操作:

  1. 确保Windows身份验证在IIS中启用,并且匿名身份验证被禁用(匿名身份验证需要的其他身份验证机制优先)
  2. 在你的web.config启用<authentication mode="Windows" />确保ASP.NET处理Windows身份验证(这应该只适用于经典管道模式)。
  3. <identity impersonate="true" />应该就够了。

您可能需要做的另一件事是确保运行AppPool的帐户可以像代理一样行事。

+3

我已经完成了所有设置,并且不起作用。你能否解释一下你最后一点的含义,*确保运行AppPool的账户可以像委托人一样行事*?我不确定你的意思,你有链接吗?谢谢 – fearofawhackplanet 2010-10-11 08:01:25

7

我写了一个辅助类,做它:

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()) 
{ 

} 

更多解释和例子,你可以在这里找到:

Impersonating CurrentUser from SYSTEM

+0

嗨,我用你的代码Console.WriteLine WindowsIdentity.GetCurrent()。名称在远程计算机上,其中另一个用户登录,使用psexec。它崩溃在行“if(OpenProcessToken(process.Handle,TOKEN_DUPLICATE,ref token))”抛出一个负面的错误代码,我无法找出它的含义。我错过了什么?谢谢。编辑:我在一个域中,其中我的用户和另一台计算机中的用户都是管理员 – Loaderon 2016-08-02 21:56:13

+0

我一直在这个问题上敲打我的头2天!使用Chrome时,每次对Active Directory的调用都会崩溃。你的班级做到了!工程就像一个魅力和易于使用!谢谢!! – Philippe 2017-01-31 03:03:10

相关问题