我正在使用代码来模拟用户帐户来访问文件共享。
public class Impersonator : IDisposable { #region Public methods. // ------------------------------------------------------------------ /// <summary> /// Constructor. Starts the impersonation with the given credentials. /// Please note that the account that instantiates the Impersonator class /// needs to have the 'Act as part of operating system' privilege set. /// </summary> /// <param name="userName">The name of the user to act as.</param> /// <param name="domainName">The domain name of the user to act as.</param> /// <param name="password">The password of the user to act as.</param> public Impersonator( string userName, string domainName, string password ) { ImpersonateValidUser( userName, domainName, password ); } // ------------------------------------------------------------------ #endregion #region IDisposable member. // ------------------------------------------------------------------ public void Dispose() { UndoImpersonation(); } // ------------------------------------------------------------------ #endregion #region P/Invoke. // ------------------------------------------------------------------ [DllImport("advapi32.dll", SetLastError=true)] private static extern int LogonUser( string lpszUserName, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] private static extern int DuplicateToken( IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken); [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] private static extern bool RevertToSelf(); [DllImport("kernel32.dll", CharSet=CharSet.Auto)] private static extern bool CloseHandle( IntPtr handle); private const int LOGON32_LOGON_INTERACTIVE = 2; private const int LOGON32_PROVIDER_DEFAULT = 0; // ------------------------------------------------------------------ #endregion #region Private member. // ------------------------------------------------------------------ /// <summary> /// Does the actual impersonation. /// </summary> /// <param name="userName">The name of the user to act as.</param> /// <param name="domainName">The domain name of the user to act as.</param> /// <param name="password">The password of the user to act as.</param> private void ImpersonateValidUser( string userName, string domain, string password ) { WindowsIdentity tempWindowsIdentity = null; IntPtr token = IntPtr.Zero; IntPtr tokenDuplicate = IntPtr.Zero; try { if ( RevertToSelf() ) { if ( LogonUser( userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token ) != 0 ) { if ( DuplicateToken( token, 2, ref tokenDuplicate ) != 0 ) { tempWindowsIdentity = new WindowsIdentity( tokenDuplicate ); impersonationContext = tempWindowsIdentity.Impersonate(); } else { throw new Win32Exception( Marshal.GetLastWin32Error() ); } } else { throw new Win32Exception( Marshal.GetLastWin32Error() ); } } else { throw new Win32Exception( Marshal.GetLastWin32Error() ); } } finally { if ( token!= IntPtr.Zero ) { CloseHandle( token ); } if ( tokenDuplicate!=IntPtr.Zero ) { CloseHandle( tokenDuplicate ); } } } /// <summary> /// Reverts the impersonation. /// </summary> private void UndoImpersonation() { if ( impersonationContext!=null ) { impersonationContext.Undo(); } } private WindowsImpersonationContext impersonationContext = null; // ------------------------------------------------------------------ #endregion }
然后使用:
using (new Impersonator("username", "domain", "password")) { Process.Start("explorer.exe", @"/root,\\server01-Prod\abc"); }
我得到一个“访问被拒绝”的错误。
这个用户可以直接访问这个共享。 我可以映射一个驱动器,使用“净使用”,但这个代码将无法正常工作。 现在我想这是代码。 有人看到什么吗? 有没有更好的方法来做到这一点?
尝试这个 :
[DllImport("advapi32.dll", SetLastError = true)] public static extern bool LogonUser( string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);
用法:
IntPtr userToken = IntPtr.Zero; bool success = External.LogonUser( "john.doe", "domain.com", "MyPassword", (int) AdvApi32Utility.LogonType.LOGON32_LOGON_INTERACTIVE, //2 (int) AdvApi32Utility.LogonProvider.LOGON32_PROVIDER_DEFAULT, //0 out userToken); if (!success) { throw new SecurityException("Logon user failed"); } using (WindowsIdentity.Impersonate(userToken)) { Process.Start("explorer.exe", @"/root,\\server01-Prod\abc"); }
如果我理解正确,你的意图是在模拟上下文中运行这个过程。
来自CreateProcess的文档(由Process.Start使用)表示:如果调用进程正在模拟另一个用户,则新进程使用该调用进程的标记,而不是模拟标记。 要在由模拟令牌表示的用户的安全上下文中运行新进程,请使用CreateProcessAsUser或CreateProcessWithLogonW函数。
所以,你使用错误的API来做到这一点。
而不是使用你的Impersonator
类,当你调用Process.Start
并传入一个包含用户名,密码和域名的ProcessStartInfo
实例时,会发生什么情况?
也许,如果这样的话,那么你的Impersonator
类应该创建一个ProcessStartInfo
实例并使用它来创建新的进程(在类中封装它)。
var psi = new ProcessStartInfo("explorer.exe", @"/root,\\server01-Prod\abc"); psi.Domain = domain; psi.UserName = username; psi.Password = password; psi.WorkingDirectory = workingDir; Process.Start(psi);
另外,根据MSDN文档 …
在ProcessStartInfo对象中设置Domain,UserName和Password属性是使用用户凭据启动进程的推荐做法。
您还应该在启动具有不同用户信誉的进程时设置工作目录。