不管是asp.net、web service还是window service,程序运行的时候只有本地计算机的部分权限,有时候需要更大的权限,比如读写某台服务器或域中的一台计算机上的文件等,这就需要更大的权限,比如域帐户权限。
通过获取不同身份的WindowsImpersonationContext对象,可以模拟不同用户登陆,请看我生成的NetworkSecurity类的
public static WindowsImpersonationContext ImpersonateUser(string strDomain,
string strLogin,
string strPwd,
LogonType logonType,
LogonProvider logonProvider);
附NetworkSecurity.cs源代码如下:
- /*
- * Author : TongWei
- * Date : 2005-1-25
- * Rights : China Netwave Inc.@2005
- */
- using System;
- using System.Runtime.InteropServices;
- using System.Security.Principal;
- using System.Security.Permissions;
- namespace CNW.OMP.Common.Utility
- {
- public enum LogonType : int
- {
- /// <summary>
- /// This logon type is intended for users who will be interactively using the computer, such as a user
- /// being logged on by a terminal server, remote shell, or similar process. This logon type has the
- /// additional expense of caching logon information for disconnected operation, and is therefore
- /// inappropriate for some client/server applications, such as a mail server.
- /// </summary>
- LOGON32_LOGON_INTERACTIVE = 2,
- /// <summary>
- /// This logon type is intended for high performance servers to authenticate clear text passwords.
- /// The LogonUser function does not cache credentials for this logon type.
- /// </summary>
- LOGON32_LOGON_NETWORK = 3,
- /// <summary>
- /// This logon type is intended for batch servers, where processes may be executing on behalf of a user
- /// without their direct intervention; or for higher performance servers that process many clear-text
- /// authentication attempts at a time, such as mail or web servers. The LogonUser function does not cache
- /// credentials for this logon type.
- /// </summary>
- LOGON32_LOGON_BATCH = 4,
- /// <summary>
- /// Indicates a service-type logon. The account provided must have the service privilege enabled.
- /// </summary>
- LOGON32_LOGON_SERVICE = 5,
- /// <summary>
- /// This logon type is intended for GINA DLLs logging on users who will be interactively using the computer.
- /// This logon type allows a unique audit record to be generated that shows when the workstation was unlocked.
- /// </summary>
- LOGON32_LOGON_UNLOCK = 7,
- /// <summary>
- /// Windows XP/2000: This logon type preserves the name and password in the authentication packages,
- /// allowing the server to make connections to other network servers while impersonating the client.
- /// This allows a server to accept clear text credentials from a client, call LogonUser, verify that
- /// the user can access the system across the network, and still communicate with other servers.
- /// </summary>
- LOGON32_LOGON_NETWORK_CLEARTEXT = 8,
- /// <summary>
- /// Windows XP/2000: This logon type allows the caller to clone its current token and specify new credentials
- /// for outbound connections. The new logon session has the same local identity, but uses different credentials
- /// for other network connections.
- /// This logon type is supported only by the LOGON32_PROVIDER_WINNT50 logon provider.
- /// </summary>
- LOGON32_LOGON_NEW_CREDENTIALS = 9
- };
- public enum LogonProvider : int
- {
- /// <summary>
- /// Use the standard logon provider for the system. The default security provider is NTLM.
- /// Windows XP: The default provider is negotiate, unless you pass NULL for the domain name and
- /// the user name is not in UPN format. In this case the default provider is NTLM.
- /// </summary>
- LOGON32_PROVIDER_DEFAULT = 0,
- /// <summary>
- /// Use the Windows NT 3.5 logon provider.
- /// </summary>
- LOGON32_PROVIDER_WINNT35 = 1,
- /// <summary>
- /// Use the NTLM logon provider.
- /// </summary>
- LOGON32_PROVIDER_WINNT40 = 2,
- /// <summary>
- /// Windows XP/2000: Use the negotiate logon provider.
- /// </summary>
- LOGON32_PROVIDER_WINNT50 = 3
- };
- class SecuUtil32
- {
- [DllImport(/"advapi32.dll/", SetLastError=true)]
- public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
- int dwLogonType, int dwLogonProvider, ref IntPtr TokenHandle);
- [DllImport(/"kernel32.dll/", CharSet=CharSet.Auto)]
- public extern static bool CloseHandle(IntPtr handle);
- [DllImport(/"advapi32.dll/", CharSet=CharSet.Auto, SetLastError=true)]
- public extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
- int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
- }
- public class NetworkSecurity
- {
- public NetworkSecurity()
- {
- //
- // TODO: Add constructor logic here
- //
- }
- /// <summary>
- /// The ImpersonateUser function attempts to log a user on to the local computer.
- /// The local computer is the computer from which ImpersonateUser was called.
- /// You cannot use ImpersonateUser to log on to a remote computer.
- /// You specify the user with a user name and domain, and authenticate the user with a clear-text password.
- /// If the function succeeds, you receive a handle to a token that represents the logged-on user.
- /// You can then use this token handle to impersonate the specified user, or in most cases,
- /// to create a process running in the context of the specified user.
- /// </summary>
- /// <param name=/"strDomain/">
- /// specifies the name of the domain or server whose account database contains the strLogin account.
- /// </param>
- /// <param name=/"strLogin/">specifies the name of the user.</param>
- /// <param name=/"strPwd/">specifies the clear-text password for the user account specified by strLogin.</param>
- /// <param name=/"logonType/">Specifies the type of logon operation to perform.</param>
- /// <param name=/"logonProvider/">Specifies the logon provider.</param>
- /// <example>
- /// //Add System.Security.dll
- /// //using System.Security.Principal;
- ///
- /// string strDomain=ConfigurationSettings.AppSettings[/"mSALoginDomainName/"];
- /// string strUser=ConfigurationSettings.AppSettings[/"mSALoginDomainUser/"];
- /// string strPassword=ConfigurationSettings.AppSettings[/"mSALoginDomainPassword/"];
- ///
- /// WindowsImpersonationContext impContext = null;
- /// try
- /// {
- /// impContext = NetworkSecurity.ImpersonateUser(strDomain,strUser,strPassword,
- /// LogonType.LOGON32_LOGON_SERVICE,
- /// LogonProvider.LOGON32_PROVIDER_DEFAULT);
- /// }
- /// catch
- /// {
- ///
- /// }
- ///
- /// //work under this logined user
- ///
- /// impContext.Undo();
- /// </example>
- /// <returns>
- /// </returns>
- public static WindowsImpersonationContext ImpersonateUser(string strDomain,
- string strLogin,
- string strPwd,
- LogonType logonType,
- LogonProvider logonProvider)
- {
- // Initialize tokens
- IntPtr tokenHandle = new IntPtr(0);
- IntPtr dupeTokenHandle = new IntPtr(0);
- tokenHandle = IntPtr.Zero;
- dupeTokenHandle = IntPtr.Zero;
- // If domain name was blank, assume local machine
- if (strDomain == /"/")
- strDomain = System.Environment.MachineName;
- try
- {
- const int SecurityImpersonation = 2;
- // Call LogonUser to obtain a handle to an access token.
- bool returnValue = SecuUtil32.LogonUser(
- strLogin,
- strDomain,
- strPwd,
- (int)logonType,
- (int)logonProvider,
- ref tokenHandle);
- // Did impersonation fail?
- if (false == returnValue)
- {
- int ret = Marshal.GetLastWin32Error();
- // Throw the exception show the reason why LogonUser failed
- string strErr = String.Format(/"LogonUser failed with error code : {0}/", ret);
- throw new ApplicationException(strErr, null);
- }
- // Get identity before impersonation
- bool retVal = SecuUtil32.DuplicateToken(tokenHandle, SecurityImpersonation, ref dupeTokenHandle);
- // Did DuplicateToken fail?
- if (false == retVal)
- {
- // Close existing handle
- SecuUtil32.CloseHandle(tokenHandle);
- // Throw the exception show the reason why DuplicateToken failed
- throw new ApplicationException(/"Failed to duplicate token/", null);
- }
- // Create new identity using new primary token
- // The token that is passed to the following constructor must
- // be a primary token in order to use it for impersonation.
- WindowsIdentity newId = new WindowsIdentity(dupeTokenHandle);
- WindowsImpersonationContext impersonatedUser = newId.Impersonate();
- return impersonatedUser;
- }
- catch (Exception ex)
- {
- throw new ApplicationException(ex.Message, ex);
- }
- finally
- {
- // Close handle
- if (tokenHandle != IntPtr.Zero)
- SecuUtil32.CloseHandle(tokenHandle);
- if (dupeTokenHandle != IntPtr.Zero)
- SecuUtil32.CloseHandle(dupeTokenHandle);
- }
- }
- }
- }