在 ASP.NET 中绕过表单身份验证以使用 Active Directory 用户身份验证






4.88/5 (13投票s)
本文描述了如何在 ASP.NET 中并行使用基于表单和基于 Active Directory 的用户身份验证过程。
引言
本文描述了如何在 ASP.NET 应用程序中,在表单身份验证之上使用 Active Directory 用户身份验证过程。
用户场景
假设我有一个大型 ASP.NET 应用程序,我使用了表单身份验证来进行用户身份验证。突然出现了一个需求,需要使用现有的 Active Directory 进行用户身份验证。我发现了两种解决方案:
- 用 Windows 身份验证替换表单身份验证
- 绕过表单身份验证以使用 Active Directory
如果 aspnet_Users.UserId
或 aspnet_Membership.UserId
列存在外键引用,则第一个选项将不起作用。
绕过表单身份验证
如果使用 ASP.NET 登录控件进行用户登录过程,则可以使用“OnAuthenticate
”事件来绕过表单身份验证。
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 设置
以下配置部分用于控制 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>
enabled
:通过在登录页面的页面加载事件中注册“OnAuthenticate
”事件,启用 Active Directory 身份验证过程。pageLevelSecurityCheck
:指示是否需要在每个页面级别进行用户身份验证检查。server
:LDAP 服务器名称或 IP 地址domain
:域名directoryPath
:用户所在的目录路径。groupName
:只有指示的用户组才能登录。filter
和filterReplace
:用于在指定的目录中搜索用户。
“ActiveDirectoryConfiguration
”类被设计和使用来映射和使用此配置。
Active Directory 连接器
此类与 Active Directory 通信,并根据 web.config 文件中设置的配置搜索用户。“IsUserLoggedIn
”方法用于此目的。
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);
}
}
通过将用户名和密码传递给“OnAuthenticate
”事件,使用此方法来检查用户是否存在以及用户是否具有访问权限。如果为 true
,则会颁发表单身份验证票证并注册到 cookie 中以创建用户登录会话。
结论
因此,可以在表单身份验证之上轻松实现来自 Active Directory 的用户身份验证。