问题描述:
--> System.Runtime.InteropServices.COMException (0x80072020): An operations error occurred.
Server stack trace:
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_AdsObject()
at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne)
at System.DirectoryServices.DirectorySearcher.FindAll()
问题原因:
在访问(Active Directory)活动目录时的安全性有关。
详见:http://support.microsoft.com/kb/329986/zh-cn
通常在不进行角色模拟的情况下,访问本地(local)AD是没有问题的;但是如果访问服务器的AD时,就会出现“出现一个操作错误”。用角色模拟就可以解决。
解决方案一:
public class IdentityImpersonation
{
/// <summary>
/// Logons the user.
/// </summary>
/// <param name="lpszUsername">The LPSZ username.</param>
/// <param name="lpszDomain">The LPSZ domain.</param>
/// <param name="lpszPassword">The LPSZ password.</param>
/// <param name="dwLogonType">Type of the dw logon.</param>
/// <param name="dwLogonProvider">The dw logon provider.</param>
/// <param name="phToken">The ph token.</param>
/// <returns></returns>
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
/// <summary>
/// Duplicates the token.
/// </summary>
/// <param name="ExistingTokenHandle">The existing token handle.</param>
/// <param name="SECURITY_IMPERSONATION_LEVEL">The SECURIT y_ IMPERSONATIO n_ LEVEL.</param>
/// <param name="DuplicateTokenHandle">The duplicate token handle.</param>
/// <returns></returns>
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
/// <summary>
/// Closes the handle.
/// </summary>
/// <param name="handle">The handle.</param>
/// <returns></returns>
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);
// 要模拟的用户的用户名、密码、域(机器名)
private String _sImperUsername;
private String _sImperPassword;
private String _sImperDomain;
//记录模拟上下文
private WindowsImpersonationContext _imperContext;
private IntPtr _adminToken;
private IntPtr _dupeToken;
// 是否已停止模拟
private Boolean _bClosed;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="impersonationUsername">所要模拟的用户的用户名</param>
/// <param name="impersonationPassword">所要模拟的用户的密码</param>
/// <param name="impersonationDomain">所要模拟的用户所在的域</param>
public IdentityImpersonation(String impersonationUsername, String impersonationPassword, String impersonationDomain)
{
_sImperUsername = impersonationUsername;
_sImperPassword = impersonationPassword;
_sImperDomain = impersonationDomain;
_adminToken = IntPtr.Zero;
_dupeToken = IntPtr.Zero;
_bClosed = true;
}
/// <summary>
/// 析构函数
/// </summary>
~IdentityImpersonation()
{
if (!_bClosed)
{
StopImpersonate();
}
}
/// <summary>
/// 开始身份角色模拟。
/// </summary>
/// <returns></returns>
public Boolean BeginImpersonate()
{
Boolean bLogined = LogonUser(_sImperUsername, _sImperDomain, _sImperPassword, 2, 0, ref _adminToken);
if (!bLogined)
{
return false;
}
Boolean bDuped = DuplicateToken(_adminToken, 2, ref _dupeToken);
if (!bDuped)
{
return false;
}
WindowsIdentity fakeId = new WindowsIdentity(_dupeToken);
_imperContext = fakeId.Impersonate();
_bClosed = false;
return true;
}
/// <summary>
/// 停止身分角色模拟。
/// </summary>
public void StopImpersonate()
{
//_imperContext.Undo();
CloseHandle(_dupeToken);
CloseHandle(_adminToken);
_bClosed = true;
}
}
但是用这种方法模拟时要注意:
public static IdentityImpersonation impersonate = new IdentityImpersonation(ADUser, ADPassword, ADDomain);
在模拟时,账户格式:domain\loginname.
<appSettings>
<!-- ADPath的格式,必须严格按照下面的格式 -->
<add key="ADPath" value="LDAP://OU=ou,DC=domain,DC=com"/>
<add key="ADAdminUser" value="domain\administrator"/>
<add key="ADPassword" value="123-aaa"/>
<add key="ADDomain" value="domain.com"/>
<!-- ImageUrl -->
</appSettings>
如果账户不对或LDAP有误,将会出项“没有注册类别”的错误
解决方案二:
using System.Web.Hosting;
...
...
// Code here runs as the logged on user
using (HostingEnvironment.Impersonate()) {
// This code runs as the application pool user
DirectorySearcher searcher ...
}
// Code here runs as logged on user again
但是,这种方法也存在不足,
详见:http://msdn.microsoft.com/en-us/library/system.web.hosting.hostingenvironment.impersonate.aspx
|
Name |
Description |
|
Impersonates the user represented by the application identity. | |
|
Impersonates the user represented by the specified user token. | |
|
Impersonates the user specified by the configuration settings for the specified virtual path, or the specified user token. |
解决方案三:
using (DirectoryEntry entry = new DirectoryEntry(strPath, ADUser, ADPassword, AuthenticationTypes.Secure))
{
using (System.DirectoryServices.DirectorySearcher mySearcher = new System.DirectoryServices.DirectorySearcher(entry))
{
// code here
}
}
直接用域用户的帐号来获得entry。