Process.Start()在模拟后抛出“拒绝访问”

我在使用Process.Start()+ Impersonation从文件服务器执行文件时遇到问题。 请帮我解决我的问题。 还有另一种方法吗?

这是按钮点击事件。

private void btnOpen_Click(object sender, EventArgs e) { try { newUser = cls.ImpersonateUser("username", "domain", "password"); string fileName = @"\\network_computer\Test\Test.doc"; System.Diagnostics.Process.Start(fileName); } catch (Exception ex) { throw ex; } finally { if (newUser != null) newUser.Undo(); } } 

这是假冒课程。

 public class clsImpersonate { #region 'Impersonation' // group type enum public enum SECURITY_IMPERSONATION_LEVEL : int { SecurityAnonymous = 0, SecurityIdentification = 1, SecurityImpersonation = 2, SecurityDelegation = 3 } // obtains user token [DllImport("advapi32.dll", SetLastError = true)] public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); // closes open handes returned by LogonUser [DllImport("kernel32.dll", CharSet = CharSet.Auto)] public extern static bool CloseHandle(IntPtr handle); // creates duplicate token handle [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle); private System.Security.Principal.WindowsImpersonationContext newUser; public WindowsImpersonationContext ImpersonateUser(string sUsername, string sDomain, string sPassword) { // initialize tokens IntPtr pExistingTokenHandle = new IntPtr(0); IntPtr pDuplicateTokenHandle = new IntPtr(0); pExistingTokenHandle = IntPtr.Zero; pDuplicateTokenHandle = IntPtr.Zero; // if domain name was blank, assume local machine if (sDomain == "") sDomain = System.Environment.MachineName; try { string sResult = null; const int LOGON32_PROVIDER_DEFAULT = 0; // create token const int LOGON32_LOGON_INTERACTIVE = 2; //const int SecurityImpersonation = 2; // get handle to token bool bImpersonated = LogonUser(sUsername, sDomain, sPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref pExistingTokenHandle); // did impersonation fail? if (false == bImpersonated) { int nErrorCode = Marshal.GetLastWin32Error(); sResult = "LogonUser() failed with error code: " + nErrorCode + "\r\n"; // show the reason why LogonUser failed //MessageBox.Show(sResult, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } // Get identity before impersonation sResult += "Before impersonation: " + WindowsIdentity.GetCurrent().Name + "\r\n"; bool bRetVal = DuplicateToken(pExistingTokenHandle, (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, ref pDuplicateTokenHandle); // did DuplicateToken fail? if (false == bRetVal) { int nErrorCode = Marshal.GetLastWin32Error(); CloseHandle(pExistingTokenHandle); // close existing handle sResult += "DuplicateToken() failed with error code: " + nErrorCode + "\r\n"; // show the reason why DuplicateToken failed //MessageBox.Show(sResult, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return null; } else { // create new identity using new primary token WindowsIdentity newId = new WindowsIdentity(pDuplicateTokenHandle); WindowsImpersonationContext impersonatedUser = newId.Impersonate(); // check the identity after impersonation sResult += "After impersonation: " + WindowsIdentity.GetCurrent().Name + "\r\n"; //MessageBox.Show(sResult, "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); return impersonatedUser; } } catch (Exception ex) { throw ex; } finally { // close handle(s) if (pExistingTokenHandle != IntPtr.Zero) CloseHandle(pExistingTokenHandle); if (pDuplicateTokenHandle != IntPtr.Zero) CloseHandle(pDuplicateTokenHandle); } } #endregion } 

如果您调试,您会看到任何错误

 bool bImpersonated = LogonUser(sUsername, sDomain, sPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref pExistingTokenHandle); 

或者在

 bool bRetVal = DuplicateToken(pExistingTokenHandle, (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, ref pDuplicateTokenHandle); 

在按钮单击事件中,尝试添加一个Using语句:

 private void btnOpen_Click(object sender, EventArgs e) { try { using (newUser = cls.ImpersonateUser("username", "domain", "password")) { string fileName = @"\\network_computer\Test\Test.doc"; System.Diagnostics.Process.Start(fileName); } } catch (Exception ex) { throw ex; } finally { if (newUser != null) newUser.Undo(); } } 

答案更新(#01):

请尝试以下代码:

 public class clsImpersonate { #region 'Impersonation' // obtains user token [DllImport("advapi32.dll", SetLastError = true)] public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); // closes open handes returned by LogonUser [DllImport("kernel32.dll", CharSet = CharSet.Auto)] public extern static bool CloseHandle(IntPtr handle); public IntPtr ImpersonateUser(string sUsername, string sDomain, string sPassword) { // initialize token IntPtr pExistingTokenHandle = new IntPtr(0); // if domain name was blank, assume local machine if (sDomain == "") sDomain = System.Environment.MachineName; try { string sResult = null; const int LOGON32_PROVIDER_DEFAULT = 0; // create token const int LOGON32_LOGON_INTERACTIVE = 2; // get handle to token bool bImpersonated = LogonUser(sUsername, sDomain, sPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref pExistingTokenHandle); // did impersonation fail? if (false == bImpersonated) { int nErrorCode = Marshal.GetLastWin32Error(); sResult = "LogonUser() failed with error code: " + nErrorCode + "\r\n"; // show the reason why LogonUser failed //MessageBox.Show(sResult, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } // Get identity before impersonation sResult += "Before impersonation: " + WindowsIdentity.GetCurrent().Name + "\r\n"; return pExistingTokenHandle; } catch (Exception ex) { throw ex; } } public bool FreeImpersonationResource(IntPtr _token) { // close handle(s) if (_token != IntPtr.Zero) return CloseHandle(_token); else return true; } #endregion } 

然后,按钮单击事件:

 private void btnOpen_Click(object sender, EventArgs e) { try { IntPtr token = cls.ImpersonateUser("username", "domain", "password"); using (WindowsImpersonationContext impersonatedUser = WindowsIdentity.Impersonate(token)) { string fileName = @"\\network_computer\Test\Test.doc"; System.Diagnostics.Process.Start(fileName); } cls.FreeImpersonationResource(token); } catch (Exception ex) { throw ex; } } 

注意:
– 如果在LogonUser函数中使用LOGON32_LOGON_INTERACTIVE ,则无需复制令牌,因为您获得的句柄是可以立即使用的主令牌。 (看看这个MSDN页面 )。
– 如果对模拟上下文使用using语句,则不需要Undo ,因为它在使用结束时“自动撤消”。
– 如果仍然无效,请尝试使用服务器的IP地址而不是其域名。
– 如果它仍然不起作用,我可以建议的最后一件事是采取原始代码并在按钮单击事件中移动整个方法ImpersonateUser ,然后执行原始指令System.Diagnostics.Process.Start(fileName); 紧跟在System.Diagnostics.Process.Start(fileName);指令之后System.Diagnostics.Process.Start(fileName);

我希望这个答案中至少有一部分会有所帮助:)

更新(#02)

我自己尝试了这个并且它正在工作,使用我之前编辑中的代码进行了以下修改:

  • clsImpersonate类中,您必须将LogonUser函数的类型更改为LOGON32_LOGON_NEW_CREDENTIALS

     // create token const int LOGON32_LOGON_INTERACTIVE = 2; const int LOGON32_LOGON_NEW_CREDENTIALS = 9; // get handle to token bool bImpersonated = LogonUser(sUsername, sDomain, sPassword, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, ref pExistingTokenHandle); 
  • 在按钮单击事件中,您必须更改使用Process.Start()的方式。 另请查看此链接以获取Process.Startfunction的一些示例

     private void button1_Click(object sender, EventArgs e) { try { IntPtr token = cls.ImpersonateUser("username", "domain", "password"); using (WindowsImpersonationContext impersonatedUser = WindowsIdentity.Impersonate(token)) { string fileName = @"Winword.exe"; // the name of the sw you will use to open your file, I suppose MS Word string argument = @"\\network_computer\Test\Test.doc"; // the path pf the file you want to open Process process = new Process(); ProcessStartInfo info = new ProcessStartInfo(); info.FileName = fileName; info.Arguments = argument; process.StartInfo = info; process.Start(); } cls.FreeImpersonationResource(token); } catch (Exception ex) { throw ex; } }