在大型的ASP.NET应用程序中,经常使用表单认证(Forms Authentication)来处理用户认证过程。然而,有时会出现需要利用现有的Active Directory(AD)来实现用户认证的需求。在这种情况下,有两种解决方案:替换表单认证为Windows认证,或者绕过表单认证以使用Active Directory。如果存在对aspnet_Users.UserId或aspnet_Membership.UserId列的外键引用,第一种方案将不可行。
如果使用ASP.NET登录控件处理用户登录过程,那么可以通过"OnAuthenticate"事件来绕过表单认证。以下是C#代码示例:
protected void LoginUser_Authenticate(object sender, AuthenticateEventArgs e)
{
try
{
if (IsActiveDirectoryEnabled)
{
if (ActiveDirectoryConnector.IsUserLoggedIn(LoginUser.UserName, LoginUser.Password))
{
e.Authenticated = true;
}
else
{
e.Authenticated = false;
}
}
}
catch (Exception ex)
{
e.Authenticated = false;
LoginUser.FailureText = ex.Message;
}
}
该事件在登录页面的页面加载事件中注册:
protected void Page_Load(object sender, EventArgs e)
{
if (IsActiveDirectoryEnabled)
{
LoginUser.Authenticate += new AuthenticateEventHandler(LoginUser_Authenticate);
}
}
以下配置部分用于控制Active Directory连接和用户搜索条件:
<ldapConfiguration enabled="true" pageLevelSecurityCheck="false" server="192.168.246.128" domain="test.com" directoryPath="DC=test,DC=com" groupName="elixtrauser" filter="(and(objectCategory=person)(objectClass=user)(samaccountname=usertosearch))" filterReplace="usertosearch">
</ldapConfiguration>
其中:
这个类与Active Directory通信,并根据web.config文件中设置的配置搜索用户。"IsUserLoggedIn"方法用于此目的。以下是C#代码示例:
public static bool IsUserLoggedIn(string userName, string password)
{
try
{
if (ActiveDirectorySettings.Enabled)
{
int startIndex = userName.IndexOf("@");
if (startIndex >= 0)
{
userName = userName.Substring(0, startIndex);
}
DirectoryEntry ldapConnection = new DirectoryEntry("LDAP://" + ActiveDirectorySettings.Server + "/" + ActiveDirectorySettings.DirectoryPath, userName, password);
DirectorySearcher searcher = new DirectorySearcher(ldapConnection);
searcher.Filter = ActiveDirectorySettings.Filter.Replace("and", "&");
searcher.Filter = searcher.Filter.Replace(ActiveDirectorySettings.FilterReplace, userName);
searcher.PropertiesToLoad.Add("memberOf");
searcher.PropertiesToLoad.Add("userAccountControl");
SearchResult directoryUser = searcher.FindOne();
if (directoryUser != null)
{
int flags = Convert.ToInt32(directoryUser.Properties["userAccountControl"][0].ToString());
if (!Convert.ToBoolean(flags & 0x0002))
{
string desiredGroupName = ActiveDirectorySettings.GroupName.ToLower();
if (desiredGroupName != string.Empty)
{
desiredGroupName = "cn=" + desiredGroupName + ",";
int numberOfGroups = directoryUser.Properties["memberOf"].Count;
bool isWithinGroup = false;
for (int i = 0; i < numberOfGroups; i++)
{
string groupName = directoryUser.Properties["memberOf"][i].ToString().ToLower();
if (groupName.Contains(desiredGroupName))
{
isWithinGroup = true;
break;
}
}
if (!isWithinGroup)
{
throw new Exception("User [" + userName + "] is not a member of the desired group.");
}
}
return true;
}
else
{
throw new Exception("User [" + userName + "] is inactive.");
}
}
else
{
throw new Exception("User [" + userName + "] not found in the specified active directory path.");
}
}
else
{
return true;
}
}
catch (LdapException ex)
{
if (ex.ErrorCode == 49)
{
throw new Exception("Invalid user authentication. Please input a valid user name & password and try again.", ex);
}
else
{
throw new Exception("Active directory server not found.", ex);
}
}
catch (DirectoryOperationException ex)
{
throw new Exception("Invalid active directory path.", ex);
}
catch (DirectoryServicesCOMException ex)
{
if (ex.ExtendedError == 8333)
{
throw new Exception("Invalid active directory path.", ex);
}
else
{
throw new Exception("Invalid user authentication. Please input a valid user name & password and try again.", ex);
}
}
catch (System.Runtime.InteropServices.COMException ex)
{
throw new Exception("Active directory server not found.", ex);
}
catch (ArgumentException ex)
{
if (ex.Source == "System.DirectoryServices")
{
throw new Exception("Invalid search filter expression.", ex);
}
else
{
throw new Exception("Unhandled exception occurred while authenticating user using active directory.", ex);
}
}
catch (Exception ex)
{
throw new Exception("Unhandled exception occurred while authenticating user using active directory.", ex);
}
}