我需要通过Directory.GetDirectories()和Directory.GetFiles()方法访问当前IPrincipal可以访问的文件和目录,而无需列出其他文件.进程本身作为NETWORK SERVICE运行,因此它必须在这些调用期间将主体更改为当前用户(通过IPrincipal).
我试图在文件访问部分之前将Thread.CurrentPrincipal更改为新的IPrincipal,但它似乎没有什么区别.
还有别的我可以做的,还是我错过了什么?
Windows模拟通过使用登录详细信息获取用户令牌来解决此问题.然后可以使用此令牌获取WindowsIdentity,然后将其用于生成模拟上下文.在此上下文范围内,您可以作为模拟用户访问文件系统.
当然,您需要存储此方法的用户名和密码才能工作.
首先,定义从Windows获取用户令牌所需的Windows API:
internal class WindowsAPI { public const int LOGON32_PROVIDER_DEFAULT = 0; public const int LOGON32_LOGON_INTERACTIVE = 2; [DllImport( "advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode )] public static extern bool LogonUser( String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken ); [DllImport( "kernel32.dll", CharSet = CharSet.Auto )] public extern static bool CloseHandle( IntPtr handle ); }
然后,使用这些API来获取WindowsIdentity:
private WindowsIdentity GetIdentity( string userName, string password ) { _userToken = IntPtr.Zero; if ( !WindowsAPI.LogonUser( userName, AbbGrainDomain, password, WindowsAPI.LOGON32_LOGON_INTERACTIVE, WindowsAPI.LOGON32_PROVIDER_DEFAULT, ref _userToken ) ) { int errorCode = Marshal.GetLastWin32Error(); throw new System.ComponentModel.Win32Exception( errorCode ); } return new WindowsIdentity( _userToken ); }
最后,使用此标识生成模拟上下文:
public ListGetDirectories( string searchPath ) { using ( WindowsImpersonationContext wic = GetIdentity().Impersonate() ) { var directories = new List (); var di = new DirectoryInfo( searchPath ); directories.AddRange( di.GetDirectories().Select( d => d.FullName ) ); return directories; } }
最后,使用存储的_userToken使用IDisposable模式清理Windows句柄非常重要:
if ( _userToken != IntPtr.Zero ) WindowsAPI.CloseHandle( _userToken );