2011-03-15 13 views
85

मैं वर्तमान उपयोगकर्ता के समूह प्राप्त करने के लिए इस कोड का उपयोग करता हूं। लेकिन मैं मैन्युअल रूप से उपयोगकर्ता को देना चाहता हूं और फिर अपने समूह प्राप्त करना चाहता हूं। मैं यह कैसे कर सकता हूँ?सक्रिय निर्देशिका में किसी उपयोगकर्ता के समूह को कैसे प्राप्त करें? (सी #, एएसपीनेट)

using System.Security.Principal; 

public ArrayList Groups() 
{ 
    ArrayList groups = new ArrayList(); 

    foreach (IdentityReference group in System.Web.HttpContext.Current.Request.LogonUserIdentity.Groups) 
    { 
     groups.Add(group.Translate(typeof(NTAccount)).ToString()); 
    } 

    return groups; 
} 

उत्तर

135

आप .NET 3.5 या ऊपर पर कर रहे हैं, आप नए System.DirectoryServices.AccountManagement (S.DS.AM) नाम स्थान जो की तुलना में इस एक बहुत आसान बना देता है का उपयोग कर सकते हैं यह हुआ करता था।

सभी इसे यहाँ के बारे में पढ़ें: Managing Directory Security Principals in the .NET Framework 3.5

अद्यतन: बड़े MSDN पत्रिका के लेख अब ऑनलाइन नहीं हैं, दुर्भाग्य से - आप download the CHM for the January 2008 MSDN magazine करने के लिए Microsoft से और आवश्यकता होगी वहाँ में लेख पढ़ें।

मूल रूप से, आप एक "प्रमुख संदर्भ" (आम तौर पर अपने डोमेन), एक उपयोगकर्ता प्रिंसिपल की आवश्यकता है, और फिर आप अपने समूहों को बहुत आसानी से मिल:

public List<GroupPrincipal> GetGroups(string userName) 
{ 
    List<GroupPrincipal> result = new List<GroupPrincipal>(); 

    // establish domain context 
    PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain); 

    // find your user 
    UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, userName); 

    // if found - grab its groups 
    if(user != null) 
    { 
     PrincipalSearchResult<Principal> groups = user.GetAuthorizationGroups(); 

     // iterate over all groups 
     foreach(Principal p in groups) 
     { 
     // make sure to add only group principals 
     if(p is GroupPrincipal) 
     { 
      result.Add((GroupPrincipal)p); 
     } 
     } 
    } 

    return result; 
} 

और कहा कि सभी वहाँ है! अब आपके पास प्राधिकरण समूहों का परिणाम (एक सूची) है जो उपयोगकर्ता से संबंधित है - उन पर पुनरावृत्ति करें, उनके नाम मुद्रित करें या जो कुछ भी आपको करना है।

अद्यतन: नहीं लगता है चाहिए: कुछ गुण है, जो UserPrincipal वस्तु पर सामने नहीं कर रहे हैं का उपयोग करने के लिए, आप अंतर्निहित DirectoryEntry में खुदाई करने के लिए की जरूरत है:

public string GetDepartment(Principal principal) 
{ 
    string result = string.Empty; 

    DirectoryEntry de = (principal.GetUnderlyingObject() as DirectoryEntry); 

    if (de != null) 
    { 
     if (de.Properties.Contains("department")) 
     { 
      result = de.Properties["department"][0].ToString(); 
     } 
    } 

    return result; 
} 

अद्यतन # 2 भी कोड के इन दो के टुकड़े को एक साथ रखा करने के लिए कठिन .... लेकिन ठीक हो - यहाँ यह जाता है:

public string GetDepartment(string username) 
{ 
    string result = string.Empty; 

    // if you do repeated domain access, you might want to do this *once* outside this method, 
    // and pass it in as a second parameter! 
    PrincipalContext yourDomain = new PrincipalContext(ContextType.Domain); 

    // find the user 
    UserPrincipal user = UserPrincipal.FindByIdentity(yourDomain, username); 

    // if user is found 
    if(user != null) 
    { 
     // get DirectoryEntry underlying it 
     DirectoryEntry de = (user.GetUnderlyingObject() as DirectoryEntry); 

     if (de != null) 
     { 
      if (de.Properties.Contains("department")) 
      { 
      result = de.Properties["department"][0].ToString(); 
      } 
     } 
    } 

    return result; 
} 
+0

@ टासिस्टो: दुर्भाग्यवश, वह संपत्ति सीधे 'उपयोगकर्ता प्रिंसिपल' पर उपलब्ध नहीं है - इसे प्राप्त करने के लिए मेरे अपडेट किए गए उत्तर को देखें। –

+0

मुझे अपने विभाग-क्षेत्र – SamekaTV

+0

@Tassito का मूल्य प्राप्त करने के लिए उपयोगकर्ता नाम देना होगा: ठीक है तो 1) डोमेन संदर्भ बनाएं, 2) उस उपयोगकर्ता को इसके नाम से ढूंढें, और 3) अपने विभाग को प्राप्त करने के लिए मेरे कोड स्निपेट का उपयोग करें –

9

एडी के भीतर प्रत्येक उपयोगकर्ता के पास memberOf है। इसमें सभी समूहों की सूची शामिल है।

यह एक छोटा सा कोड उदाहरण है:

// (replace "part_of_user_name" with some partial user name existing in your AD) 
var userNameContains = "part_of_user_name"; 

var identity = WindowsIdentity.GetCurrent().User; 
var allDomains = Forest.GetCurrentForest().Domains.Cast<Domain>(); 

var allSearcher = allDomains.Select(domain => 
{ 
    var searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + domain.Name)); 

    // Apply some filter to focus on only some specfic objects 
    searcher.Filter = String.Format("(&(&(objectCategory=person)(objectClass=user)(name=*{0}*)))", userNameContains); 
    return searcher; 
}); 

var directoryEntriesFound = allSearcher 
    .SelectMany(searcher => searcher.FindAll() 
     .Cast<SearchResult>() 
     .Select(result => result.GetDirectoryEntry())); 

var memberOf = directoryEntriesFound.Select(entry => 
{ 
    using (entry) 
    { 
     return new 
     { 
      Name = entry.Name, 
      GroupName = ((object[])entry.Properties["MemberOf"].Value).Select(obj => obj.ToString()) 
     }; 
    } 
}); 

foreach (var item in memberOf) 
{ 
    Debug.Print("Name = " + item.Name); 
    Debug.Print("Member of:"); 

    foreach (var groupName in item.GroupName) 
    { 
     Debug.Print(" " + groupName); 
    } 

    Debug.Print(String.Empty); 
} 
} 
+1

@ टासिस्टो: हाँ, वह आपको समझता है। उपरोक्त कोड स्निपेट ठीक वैसे ही करेगा जैसा आपको पसंद है। केवल अंतिम लूप लूप को एक लूप के साथ प्रतिस्थापित करें जो डीबग प्रिंटिंग के बजाय समूह नामों की एक सूची उत्पन्न करता है। –

+2

यह उपयोगकर्ता के प्राथमिक समूह (अक्सर डोमेन उपयोगकर्ता) को सूचीबद्ध करने में विफल रहेगा। आपको वापस जाना होगा और उस जानकारी के लिए अलग से पूछना होगा। GetAuthorizationGroups में यह समस्या नहीं है। – Andy

+0

@ एंडी: ठीक है, जानना अच्छा है। – Oliver

45

GetAuthorizationGroups() n करता है ओस्टेड समूहों को ढूंढें। वास्तव में सभी समूहों उसे किसी उपयोगकर्ता (नेस्टेड समूहों सहित) का एक सदस्य है पाने के लिए, इस प्रयास करें:

using System.Security.Principal 

private List<string> GetGroups(string userName) 
{ 
    List<string> result = new List<string>(); 
    WindowsIdentity wi = new WindowsIdentity(userName); 

    foreach (IdentityReference group in wi.Groups) 
    { 
     try 
     { 
      result.Add(group.Translate(typeof(NTAccount)).ToString()); 
     } 
     catch (Exception ex) { } 
    } 
    result.Sort(); 
    return result; 
} 

मैं try/catch उपयोग करें, क्योंकि मैं एक बहुत बड़ी ईस्वी में 2 200 में से समूहों के साथ कुछ अपवाद था, क्योंकि कुछ SIDs अब उपलब्ध नहीं थे। (Translate() कॉल एक एसआईडी -> नाम रूपांतरण करता है।)

+2

एडी के माध्यम से चलाने के बजाए इस तकनीक का उपयोग करके प्रदर्शन में सुधार किया गया। धन्यवाद आप! – Philippe

1

मेरे मामले में मैं किसी भी बहिष्कार के बिना GetGroups() का उपयोग करने का एकमात्र तरीका उस उपयोगकर्ता को उपयोगकर्ता (USER_WITH_PERMISSION) जोड़ रहा था जिसमें एडी पढ़ने की अनुमति है (सक्रिय निर्देशिका)। इस उपयोगकर्ता और पासवर्ड को पास करने वाले प्रिंसिपल कॉन्टेक्स्ट को बनाना बेहद जरूरी है।

var pc = new PrincipalContext(ContextType.Domain, domain, "USER_WITH_PERMISSION", "PASS"); 
var user = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, userName); 
var groups = user.GetGroups(); 

कदम आप सक्रिय निर्देशिका के अंदर अनुसरण कर सकते हैं पाने के लिए यह काम कर रहा:

  1. Into Active Directory create a group (or take one) and under secutiry tab add "Windows Authorization Access Group"
  2. Click on "Advanced" button
  3. Select "Windows Authorization Access Group" and click on "View"
  4. Check "Read tokenGroupsGlobalAndUniversal"
  5. Locate the desired user and add to the group you created (taken) from the first step
+1

यदि आप अपने वेब एप्लिकेशन में किसी सेवा/ऐप पूल खाते के लिए अंतर्निहित खाते का उपयोग करते हैं तो यह संभवतः खेल में आता है। यदि आप सेवा/ऐप पूल खाते के रूप में डोमेन खाते का उपयोग करते हैं, या कोड के भीतर एक डोमेन खाते का प्रतिरूपण करते हैं, इसे डिफ़ॉल्ट रूप से अधिकारों को पढ़ना चाहिए और इस समस्या को नहीं होना चाहिए। – vapcguy

10

सबसे पहले, GetAuthorizationGroups() के लिए एक महान कार्य है लेकिन दुर्भाग्य से 2 नुकसान हैं:

  1. प्रदर्शन गरीब है, खासकर बड़ी कंपनियों में कई उपयोगकर्ताओं और समूहों के साथ। यह बहुत अधिक डेटा प्राप्त करता है, तो आपको वास्तव में
  2. में प्रत्येक लूप पुनरावृत्ति के लिए सर्वर कॉल की आवश्यकता होती है जिसमें इसमें बग शामिल हैं जो आपके एप्लिकेशन को 'कुछ दिन' काम करना बंद कर सकती हैं जब समूह और उपयोगकर्ता विकसित हो रहे हैं। माइक्रोसॉफ्ट ने इस मुद्दे को पहचाना और कुछ एसआईडी से संबंधित है। आपको जो त्रुटि मिलेगी वह है "समूह की गणना करते समय एक त्रुटि हुई"

इसलिए, मैंने बेहतर प्रदर्शन और त्रुटि-सुरक्षित के साथ GetAuthorizationGroups() को प्रतिस्थापित करने के लिए एक छोटा सा फ़ंक्शन लिखा है। यह अनुक्रमित फ़ील्ड का उपयोग कर एक क्वेरी के साथ केवल 1 एलडीएपी कॉल करता है। यदि आपको समूह नामों ("सीएन" संपत्ति) की तुलना में अधिक गुणों की आवश्यकता होती है तो इसे आसानी से बढ़ाया जा सकता है।

// Usage: GetAdGroupsForUser2("domain\user") or GetAdGroupsForUser2("user","domain") 
public static List<string> GetAdGroupsForUser2(string userName, string domainName = null) 
{ 
    var result = new List<string>(); 

    if (userName.Contains('\\') || userName.Contains('/')) 
    { 
     domainName = userName.Split(new char[] { '\\', '/' })[0]; 
     userName = userName.Split(new char[] { '\\', '/' })[1]; 
    } 

    using (PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, domainName)) 
     using (UserPrincipal user = UserPrincipal.FindByIdentity(domainContext, userName)) 
      using (var searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + domainContext.Name))) 
      { 
       searcher.Filter = String.Format("(&(objectCategory=group)(member={0}))", user.DistinguishedName); 
       searcher.SearchScope = SearchScope.Subtree; 
       searcher.PropertiesToLoad.Add("cn"); 

       foreach (SearchResult entry in searcher.FindAll()) 
        if (entry.Properties.Contains("cn")) 
         result.Add(entry.Properties["cn"][0].ToString()); 
      } 

    return result; 
} 
+0

बहुत बढ़िया! Thanx। मैंने कुछ कोड लिखना शुरू किया और GetAuthorizationGroups का उपयोग कर रहा था और यह डर था कि यह 300ms-2.5s ले रहा था सभी समूह प्राप्त करें। आपकी विधि 20-30 एमएस में की जाती है। – Keith

+2

यह आशाजनक लग रहा था, लेकिन यह नेस्टेड समूहों को हल नहीं करता है, उदा। उपयोगकर्ता समूह ए का सदस्य होता है, जो स्वयं समूह एक्स का सदस्य होता है।उपरोक्त कोड केवल समूह को दिखाएगा, लेकिन समूह एक्स नहीं। मैंने टोकन समूह के माध्यम से इस विधि का उपयोग किया: http://stackoverflow.com/a/4460658/602449 –

संबंधित मुद्दे