सक्रिय निर्देशिका में उपयोगकर्ता के समूह कैसे प्राप्त करें? (c #, asp.net)


109

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

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;
}

जवाबों:


163

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

इसके बारे में यहाँ पढ़ें: .NET ढाँचा 3.5 में निर्देशिका सुरक्षा प्रधानाचार्य

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

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

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;
}

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

मुझे अपने प्रस्थान-क्षेत्र का मूल्य प्राप्त करने के लिए उपयोगकर्ता नाम देने की आवश्यकता है
टासीस्टो

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

1
गेटग्रुप्स विधि ने मेरे लिए काम नहीं किया, मैंने कंस्ट्रक्टर के एक और अधिभार का उपयोग करने के लिए नया प्रिंसिपल संदर्भ बदल दिया: प्रिंसिपल कॉन्टेक्स्ट yourDomain = new PrincipalContext (ContextType.Domain, "192.168.2.23", "domain \ user", "पासवर्ड" ); यह पूरी तरह से तार्किक है क्योंकि आप हमेशा सक्रिय निर्देशिका प्रमाणीकरण के माध्यम से लॉग इन नहीं होते हैं। आशा है कि यह मदद करता है
ओमिड एस।

2
यह उत्तर उत्कृष्ट है। यह भी संभव है कि समूहों के पुनरावृत्ति को सरल बनाया जाए: result.AddRange (user.GetAuthorizationGroups) () .Type <GroupPrincipal> ()
tlbignerd

59

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

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क्योंकि मेरे पास 200 में से 2 समूहों के साथ कुछ अपवाद बहुत बड़े ईस्वी सन् में थे क्योंकि कुछ SID अब उपलब्ध नहीं थे। ( Translate()कॉल एक SID -> नाम रूपांतरण करता है।)


3
AD के माध्यम से चलने के बजाय इस तकनीक का उपयोग करके प्रदर्शनों में सुधार किया गया। धन्यवाद!
फिलिप

GetAuthorisationGroups () मेरे लिए सुपर स्लो है यानी 26 और मेरे द्वारा अब तक पाए गए अन्य सभी कोडों में सभी, डोमेन उपयोगकर्ता आदि जैसे जाने-माने पहचानकर्ता शामिल नहीं हैं ... आपके द्वारा प्रदान किया गया कोड शाब्दिक रूप से तत्काल है और इसमें सभी sids, हाँ केवल sids लेकिन यही मुझे अच्छी तरह से ज्ञात और कस्टम लोगों सहित की आवश्यकता है!
थियरी

19

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

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

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

// 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;
}

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

4
यह आशाजनक लग रहा था, लेकिन यह नेस्टेड समूहों को हल नहीं करता है, उदाहरण के लिए एक उपयोगकर्ता समूह का सदस्य है, जो स्वयं समूह x का सदस्य है। ऊपर दिया गया कोड केवल समूह a को दिखाएगा, लेकिन समूह x को नहीं। मैंने इस विधि का उपयोग
टोकनग्रुप्स के

रॉबर्ट Muehsig की टिप्पणी पर एक नज़र डालें - यह समूहों को नेस्टेड करता है और और भी तेज है। केवल नीचे की ओर यह केवल सुरक्षा समूह नहीं वितरित करता है वितरण समूह
निक रुबिनो

@bigjim GetAuthorizationGroups का उपयोग नहीं कर सकता क्योंकि इसके डेटा को वापस करने के लिए लगभग 6 सेकंड लगते हैं, लेकिन आपके द्वारा प्रदान किया गया कोड सभी, डोमेन उपयोगकर्ताओं, आदि जैसे प्रसिद्ध समूहों को वापस नहीं करता है ... और मुझे ये चाहिए। वहाँ सब कुछ केवल "कस्टम समूहों" को वापस करने के लिए लगता है और प्रत्येक समूह जो एक उपयोगकर्ता से संबंधित नहीं है।
थियरी

11

AD के भीतर प्रत्येक उपयोगकर्ता के पास एक संपत्ति है 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 के पास यह समस्या नहीं है।
एंडी

1

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

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

इसे प्राप्त करने के लिए आप सक्रिय निर्देशिका के अंदर आने वाले चरणों का पालन कर सकते हैं:

  1. सक्रिय निर्देशिका में एक समूह बनाएं (या एक लें) और सेकंडरी टैब के तहत "विंडोज प्राधिकरण एक्सेस ग्रुप" जोड़ें
  2. "उन्नत" बटन पर क्लिक करें
  3. "विंडोज प्राधिकरण एक्सेस ग्रुप" चुनें और "देखें" पर क्लिक करें
  4. "टोकन पढ़ें"
  5. वांछित उपयोगकर्ता का पता लगाएँ और पहले चरण से आपके द्वारा बनाए गए समूह में जोड़ें

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

1

यह मेरे लिए काम करता है

public string[] GetGroupNames(string domainName, string userName)
    {
        List<string> result = new List<string>();

        using (PrincipalContext principalContext = new PrincipalContext(ContextType.Domain, domainName))
        {
            using (PrincipalSearchResult<Principal> src = UserPrincipal.FindByIdentity(principalContext, userName).GetGroups())
            {
                src.ToList().ForEach(sr => result.Add(sr.SamAccountName));
            }
        }

        return result.ToArray();
    }

1

उत्तर इस बात पर निर्भर करता है कि आप किस प्रकार के समूहों को पुनः प्राप्त करना चाहते हैं। System.DirectoryServices.AccountManagementनाम स्थान दो समूह पुनः प्राप्ति के तरीकों प्रदान करता है:

GetGroups - समूह ऑब्जेक्ट्स का एक संग्रह लौटाता है जो उन समूहों को निर्दिष्ट करता है जिनमें वर्तमान प्रिंसिपल एक सदस्य है।

यह अतिभारित विधि केवल उन समूहों को वापस करती है जिनमें से प्रिंसिपल सीधे सदस्य हैं; कोई पुनरावर्ती खोज नहीं की जाती है।

GetAuthorizationGroups - मुख्य वस्तुओं का एक संग्रह लौटाता है जिसमें सभी प्राधिकरण समूह होते हैं जिसमें यह उपयोगकर्ता एक सदस्य होता है। यह फ़ंक्शन केवल उन समूहों को वापस करता है जो सुरक्षा समूह हैं; वितरण समूहों को वापस नहीं किया जाता है।

यह विधि सभी समूहों को पुनरावर्ती खोजती है और उन समूहों को वापस करती है जिसमें उपयोगकर्ता सदस्य है। लौटे सेट में अतिरिक्त समूह भी शामिल हो सकते हैं जो सिस्टम उपयोगकर्ता को प्राधिकरण के प्रयोजनों के लिए सदस्य मानेंगे।

तो GetGroupsहो जाता है सभी समूहों उपयोगकर्ता एक है, जिनमें से प्रत्यक्ष सदस्य है, और GetAuthorizationGroupsसब हो जाता है प्राधिकरण समूहों उपयोगकर्ता एक है, जिनमें से प्रत्यक्ष या अप्रत्यक्ष सदस्य।

जिस तरह से उनका नाम लिया गया है, उसके बावजूद एक दूसरे का सबसेट नहीं है। वहाँ समूहों द्वारा GetGroupsवापस नहीं लौटा जा सकता है GetAuthorizationGroups, और इसके विपरीत।

यहाँ एक उपयोग उदाहरण है:

PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, "MyDomain", "OU=AllUsers,DC=MyDomain,DC=Local");
UserPrincipal inputUser = new UserPrincipal(domainContext);
inputUser.SamAccountName = "bsmith";
PrincipalSearcher adSearcher = new PrincipalSearcher(inputUser);
inputUser = (UserPrincipal)adSearcher.FindAll().ElementAt(0);
var userGroups = inputUser.GetGroups();

1

मेरा समाधान:

UserPrincipal user = UserPrincipal.FindByIdentity(new PrincipalContext(ContextType.Domain, myDomain), IdentityType.SamAccountName, myUser);
List<string> UserADGroups = new List<string>();            
foreach (GroupPrincipal group in user.GetGroups())
{
    UserADGroups.Add(group.ToString());
}

0

मामले में अनुवाद स्थानीय रूप से काम करता है लेकिन दूरस्थ रूप से ईआई समूह नहीं। अनुवाद (typeof (NTAccount)

यदि आप चाहते हैं कि ऐप्लिकेशन कोड का उपयोग लॉगग्रेड इन USER पहचान का उपयोग करके किया जाए, तो प्रतिरूपण सक्षम करें। प्रतिरूपण को IIS के माध्यम से या web.config में निम्नलिखित तत्व जोड़कर सक्षम किया जा सकता है ।

<system.web>
<identity impersonate="true"/>

यदि प्रतिरूपण सक्षम है, तो एप्लिकेशन आपके उपयोगकर्ता खाते में पाई गई अनुमतियों का उपयोग करके निष्पादित करता है। इसलिए यदि लॉग इन उपयोगकर्ता के पास किसी विशिष्ट नेटवर्क संसाधन तक पहुंच है, तभी वह उस संसाधन को एप्लिकेशन के माध्यम से एक्सेस कर पाएगा।

इस जानकारी के लिए अपने मेहनती वीडियो से PRAGIM टेक का धन्यवाद करें

Asp.net भाग 87 में विंडोज प्रमाणीकरण:

https://www.youtube.com/watch?v=zftmaZ3ySMc

लेकिन प्रतिरूपण सर्वर पर बहुत अधिक ओवरहेड बनाता है

कुछ नेटवर्क समूहों के उपयोगकर्ताओं को अनुमति देने का सबसे अच्छा समाधान वेब कॉन्फ़िगरेशन में अनाम से इनकार करना है <authorization><deny users="?"/><authentication mode="Windows"/>

और पीछे आपके कोड में, अधिमानतः Global.asax में, HttpContext.Current.User.IsInRole का उपयोग करें :

Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
If HttpContext.Current.User.IsInRole("TheDomain\TheGroup") Then
//code to do when user is in group
End If

नोट: समूह को एक बैकस्लैश \ "TheDomain \ TheGroup" के साथ लिखा जाना चाहिए

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.