65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (13投票s)

2011 年 10 月 9 日

CPOL

2分钟阅读

viewsIcon

82136

downloadIcon

3669

本文描述了如何在 ASP.NET 中并行使用基于表单和基于 Active Directory 的用户身份验证过程。

引言

本文描述了如何在 ASP.NET 应用程序中,在表单身份验证之上使用 Active Directory 用户身份验证过程。

用户场景

假设我有一个大型 ASP.NET 应用程序,我使用了表单身份验证来进行用户身份验证。突然出现了一个需求,需要使用现有的 Active Directory 进行用户身份验证。我发现了两种解决方案:

  • 用 Windows 身份验证替换表单身份验证
  • 绕过表单身份验证以使用 Active Directory

如果 aspnet_Users.UserIdaspnet_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:只有指示的用户组才能登录。
  • filterfilterReplace:用于在指定的目录中搜索用户。

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 的用户身份验证。

© . All rights reserved.