2010-02-01 128 views
1

我该如何去迭代组以找出给定用户是否为组的成员?检查活动目录组成员身份

我知道我可以在WindowsPrincipal对象上使用IsInRole,但由于某些原因,它并不总是为我工作,它不会出错或抛出异常,但只是返回false。

我把下面的代码放在一起,可以帮助我在可靠性方面进行改进,它在3周的测试中没有给出任何错误的结果。

附注:1:因此我无法使用GC访问AD用户名和密码。 2:可以在任何域中创建组,但在同一个林中。 3:组可以拥有来自各个域和组的用户。

感谢

KA

 [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] 
    static extern int CheckTokenMembership(int TokenHandle, byte[] PSID, out bool IsMember); 

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)] 
    static extern bool IsValidSid(byte[] PSID); 


private bool Authenticate(XmlNodeList XmlNodeGroups) 
    { 
     bool result = false; 
     try 
     { 
      Dictionary<string, List<string>> Groups = GetGroups(XmlNodeGroups); 
      //search global catalog and get SID of the group 
      Byte[] sid = null; 
      foreach (string groupName in Groups.Keys) 
      { 
       using (DirectoryEntry entry = new DirectoryEntry("GC:")) 
       { 
        IEnumerator ie = entry.Children.GetEnumerator(); 
        ie.MoveNext(); 
        using (DirectorySearcher ds = new DirectorySearcher((DirectoryEntry)ie.Current)) 
        { 
         ds.Filter = string.Format("(&(|(sAMAccountName={0}))(objectClass=group))", groupName); 
         using (SearchResultCollection resColl = ds.FindAll()) 
         { 
          if (resColl.Count > 0) 
          { 
           ResultPropertyCollection resultPropColl = resColl[0].Properties; 
           sid = (byte[])resultPropColl["objectsid"][0]; 
           if (sid == null || !IsValidSid(sid)) 
           { 
            // log message and continue to next group          continue; 
           } 
          } 
          else 
          { 
            // log message and continue to next group         continue; 
          } 
         } 

         bool bIsMember = false; 
         if (CheckTokenMembership(0, sid, out bIsMember) == 0) 
         { 
           // log message and initiate fall back....... use Legacy 
          result = CheckMemberOf(XmlNodeGroups, _CurrentIdentity); 
          break; 
         } 
         else 
         { 
          result = bIsMember ? true : false; 
          if (result) 
          { 
           // debug message         break; 
          } 
          else 
          { 
           // debug message 
          } 
         } 
        } 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      // log exception message and initiate fall back....... use Legacy 
      result = CheckMemberOf(XmlNodeGroups, _CurrentIdentity); 
     } 
     return result; 
    }</code> 

回答

2

Are you on .NET 3.5 ? If so, check out the MSDN magazine article Managing Directory Security Principals in the .NET Framework 3.5 . It shows just how much easier things have become when it comes to users and groups in AD.

As for your requirement - you could

  • find the group in question
  • enumerate all its members
  • find if your given user is a member in that group

and all this can be done quite easily with the help of the System.DirectoryServices.AccountManagement命名空间:

// establish a context - define a domain (NetBIOS style name), 
// or use the current one, when not specifying a specific domain 
PrincipalContext ctx = new PrincipalContext(ContextType.Domain); 

// find the group in question 
GroupPrincipal theGroup = GroupPrincipal.FindByIdentity(ctx, "nameOfGroup"); 

// recursively enumerate the members of the group; making the search 
// recursive will also enumerate the members of any nested groups 
PrincipalSearchResult<Principal> result = theGroup.GetMembers(true); 

// find the user in the list of group members 
UserPrincipal user = (result.FirstOrDefault(p => p.DisplayName == "Some Name") as UserPrincipal); 

// if found --> user is member of this group, either directly or recursively 
if(user != null) 
{ 
    // do something with the user 
} 
+0

我仍然使用.Net v2.0,并且没有计划将它移动到3.5。我想我们今年下半年会直接进入v4.0。 – TheOCD 2010-02-02 08:58:02

+0

非常感谢您的回复。这正是我一直在寻找的。但是我看到的是代码太慢,因为它是递归的。代码行: //在组成员列表中找到用户 UserPrincipal user =(result.FirstOrDefault(p => p.DisplayName ==“Some Name”)as UserPrincipal); 在尝试解析包含大量用户的组时非常慢。任何帮助。 – Ashish 2010-12-20 06:08:27

+0

@Ashish:如果你不想让它递归,那就改用'GetMembers(false)'。这应该会让事情变得相当糟糕 – 2010-12-20 07:30:06

0

我试图用你的代码段中的3.5框架,此行我的编译器说,这是不正确的:

// find the user in the list of group members 
    UserPrincipal user = (result.FirstOrDefault(p => p.DisplayName == adUser) as UserPrincipal); 

特别是result.FirstOfDefault,它sa这不是一个有效的选择。

谢谢!

+1

请包括System.Linq命名空间,它应该工作正常。 – Ashish 2010-12-20 07:17:51