使用C#从Active Directory获取组

7

我在使用System.DirectoryServices时遇到了从Active Directory获取组的问题。

最初,我在一个注册在域上的计算机上启动了我的应用程序,但由于它是一个活动域,我不想对AD进行任何写操作,因此我在一台Windows XP主机操作系统上安装了Windows Server 2003虚拟机。

我在机器上添加了另一个以太网端口并设置了交换机,其中1个以太网端口专用于虚拟机,另一个端口用于主机。

在配置IP地址以进行通信后,我将我的应用程序转移到主机机器上并启动它,但是我遇到了一个DirectoryServicesCOMException异常。

错误信息显示用户名和密码无效:( 为了检查是否是Active Directory的问题,我创建了第三个虚拟机并安装了Windows XP,并使用APP中测试过的凭据将其添加到域中,一切正常。

所以我认为问题可能是应用程序运行的机器不是域的一部分。

这是导致问题的代码块:

public CredentialValidation(String Domain, String Username, String Password, Boolean Secure)
{
     //Validate the Domain!
     try
     {
         PrincipalContext Context = new PrincipalContext(ContextType.Domain, Domain); //Throws Exception
         _IsValidDomain = true;

         //Test the user login
         _IsValidLogin = Context.ValidateCredentials(Username, Password);

         //Check the Group Admin is within this user
         //******HERE
         var Results = UserPrincipal.FindByIdentity(Context, Username).GetGroups(Context);

         foreach(Principal Result in Results)
         {
             if (Result.SamAccountName == "Domain Admins")
             {
                 _IsAdminGroup = true;
                 break;
             }
         }
         Results.Dispose();
         Context.Dispose();
     }
     catch (PrincipalServerDownException)
     {
         _IsValidDomain = false;
     }
 }

登录对话框中的信息输入如下:
Domain: test.internal
Username: testaccount
Password: Password01

希望有人能够解决这个错误。


更新:

在检查服务器的安全日志后,我发现我的登录尝试是成功的,但这是因为:

_IsValidLogin = Context.ValidateCredentials(Username, Password);

我在检查组后面的那一行代码出现了错误,因此主要问题是以下代码行在未加入网络的机器上无法正常工作:

var Results = UserPrincipal.FindByIdentity(Context, Username).GetGroups(Context);

你确定方法输入的用户凭据对于你尝试验证的给定域是正确的吗?这个用户真的存在吗?你尝试过使用System.DirectoryServices命名空间中的DirectoryEntryDirectorySearcher类进行传统的方法吗?这只是建议,我对Principal对象并不了解。 - Will Marcouiller
由于我在网络上放置了另一台VM XP机器并使用相同的凭据,因此用户已存在。我可以在AD中看到该用户,并通过在cmd中运行命令start \\server1来获取凭据对话框并能够进行身份验证。这在网络中的计算机上100%有效。 - RobertPitt
2个回答

2
根据你的代码片段,在调用ValidateCredentials之前尝试创建PrincipalContext时失败了。此时运行代码的线程仍在使用本地标识(如果在Web进程中)或您登录机器时使用的标识(对于Windows进程)。这两者都不存在于test.internal域中。
你可以尝试使用包含用户名和密码的构造函数重载的PrincipalContext。请参见http://msdn.microsoft.com/en-us/library/bb341016.aspx

我理解了,但是如果PrincipalContext失败了,为什么在我的服务器日志的安全日志中我可以看到来自客户端PC的用户名成功登录,我有一种感觉这与本地Windows身份有关,但我已经尝试过:TEST/testaccounttestaccount@test以及testaccount@test.internal,所有都失败了。我也确定我尝试过Principle Context方法的重载,我会再试一次并更新。 - RobertPitt
哇,我确定测试过了 :/,代码行 'PrincipalContext(ContextType.Domain, Domain);' 已经被更新为包含用户名和密码,并且现在似乎工作正常。 - RobertPitt

2

我曾经通过C# .NET进行过相当多的用户管理。我找到了一些你可以尝试的方法。

以下两种方法将为给定的SAM帐户名称获取DirectoryEntry对象。它需要一个DirectoryEntry,该对象是您想要开始搜索帐户的OU的根目录。

另一个方法将为您提供用户所属组的可分辨名称列表。然后,您可以使用这些DN来搜索AD并获取DirectoryEntry对象。

public List<string> GetMemberOf(DirectoryEntry de)
{
  List<string> memberof = new List<string>();

  foreach (object oMember in de.Properties["memberOf"])
  {
    memberof.Add(oMember.ToString());
  }

  return memberof;
}

public DirectoryEntry GetObjectBySAM(string sam, DirectoryEntry root)
{
  using (DirectorySearcher searcher = new DirectorySearcher(root, string.Format("(sAMAccountName={0})", sam)))
  {
    SearchResult sr = searcher.FindOne();

    if (!(sr == null)) return sr.GetDirectoryEntry();
    else
      return null;
  }
}

这里使用了 Directory Entry,但我不想在认证过程中使用它。DirectoryServices 有一个用于处理的内置命名空间叫做 AccountManagement - RobertPitt
是的,我只是在谈论根据您问题的标题获取用户所属组列表的方法。 - Frank Hale

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接