অ্যাক্টিভ ডিরেক্টরিতে কোনও ব্যবহারকারীর গ্রুপগুলি কীভাবে পাবেন? (সি #, এসপি নেট)


109

আমি বর্তমান ব্যবহারকারীর দলগুলি পেতে এই কোডটি ব্যবহার করি। তবে আমি নিজে ব্যবহারকারীকে দিতে এবং তার গ্রুপগুলি পেতে চাই get কিভাবে আমি এটি করতে পারব?

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(এসডিএস.এএম) নাম স্থানটি ব্যবহার করতে পারেন যা এটি আগের চেয়ে অনেক সহজ করে তোলে।

এটি সম্পর্কে সমস্ত এখানে পড়ুন: .NET ফ্রেমওয়ার্ক 3.5 তে ডিরেক্টরি সুরক্ষা অধ্যক্ষগুলি পরিচালনা করা

আপডেট: পুরানো এমএসডিএন ম্যাগাজিনের আর্টিকেলগুলি আর অনলাইনে নেই, দুর্ভাগ্যক্রমে - আপনাকে মাইক্রোসফ্ট থেকে ২০০৮ সালের জানুয়ারির এমএসডিএন ম্যাগাজিনের জন্য সিএইচএম ডাউনলোড করতে হবে এবং সেখানে নিবন্ধটি পড়তে হবে।

মূলত, আপনার একটি "প্রধান প্রসঙ্গ" (সাধারণত আপনার ডোমেন), একজন ব্যবহারকারী অধ্যক্ষ হওয়া দরকার এবং তারপরে আপনি খুব সহজেই এর গ্রুপগুলি পান:

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
গেটগ্রুপস পদ্ধতিটি আমার পক্ষে কাজ করে নি, আমি নিম্নলিখিতভাবে নির্মাণকারীর আরেকটি ওভারলোড ব্যবহার করতে নতুন মূল প্রসঙ্গে পরিবর্তন করেছি: অধ্যক্ষকন্টেক্সট আপনারডোমাইন = নতুন অধ্যক্ষকন্টেক্সট (কনটেক্সটটাইপ.ডোমেন, "192.168.2.23", "ডোমেন \ ব্যবহারকারী", "পাসওয়ার্ড" ); আপনি সম্পূর্ণ সক্রিয় ডিরেক্টরি প্রমাণীকরণের মাধ্যমে লগ ইন না থাকায় এটি সম্পূর্ণ যৌক্তিক। আশা করি এটি সহায়তা করে
ওমিদ এস

2
এই উত্তরটি দুর্দান্ত। গোষ্ঠীগুলির পুনরাবৃত্তিগুলি এখানে সহজতর করাও সম্ভব: ফলাফল.এডড্রেঞ্জ (ইউজার.গেটঅর্ট্রাইজেশনগ্রুপস) (অফ। টাইপ <গ্রুপ গ্রুপ:)
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 টির সাথে আমার কিছু ব্যতিক্রম ছিল কারণ কিছু এসআইডি আর উপলব্ধ ছিল না। ( Translate()কলটি একটি এসআইডি করে -> নাম রূপান্তর করে))


3
পারফরম্যান্স এডি মাধ্যমে চালানোর পরিবর্তে এই কৌশলটি ব্যবহার করে উন্নত হয়েছিল। ধন্যবাদ!
ফিলিপ

GetAuthorisationGroups () আমার জন্য অত্যন্ত ধীর অর্থাৎ ২ 26 এবং আমি এখনও অবধি খুঁজে পেয়েছি এমন অন্য কোডগুলিতে প্রত্যেকের, ডোমেন ব্যবহারকারীগণ ইত্যাদির মতো সুপরিচিত সনাক্তকারীকে অন্তর্ভুক্ত করা হয়নি ... আপনি যে কোডটি সরবরাহ করেছেন তা আক্ষরিকভাবে তাত্ক্ষণিক এবং এতে সমস্ত এসিড, হ্যাঁ কেবল সিডস তবে এটিই আমার প্রয়োজন, সুপরিচিত এবং কাস্টমগুলি সহ!
থিয়েরি

19

প্রথমত, GetAuthorizationGroups () একটি দুর্দান্ত ফাংশন তবে দুর্ভাগ্যক্রমে এর 2 টি অসুবিধা রয়েছে:

  1. পারফরম্যান্স খুব কম, বিশেষত অনেক ব্যবহারকারী এবং গোষ্ঠী সহ বড় সংস্থায়। এটি আপনাকে আরও অনেক বেশি তথ্য এনেছে এবং ফলস্বরূপ প্রতিটি লুপ পুনরাবৃত্তির জন্য একটি সার্ভার কল করে
  2. এটিতে এমন বাগ রয়েছে যা গোষ্ঠী এবং ব্যবহারকারীরা যখন বিকশিত হয় তখন আপনার অ্যাপ্লিকেশনটি 'কোনও দিন' কাজ বন্ধ করে দিতে পারে। মাইক্রোসফ্ট বিষয়টি স্বীকৃতি দিয়েছে এবং কিছু এসআইডি'র সাথে সম্পর্কিত। আপনি যে ত্রুটিটি পাবেন সেটি হ'ল "দলগুলি গণনার সময় একটি ত্রুটি ঘটেছে"

অতএব, আমি আরও ভাল পারফরম্যান্স এবং ত্রুটি-নিরাপদ সাথে GetAuthorizationGroups () প্রতিস্থাপন করতে একটি ছোট ফাংশন লিখেছি। এটি সূচকযুক্ত ক্ষেত্রগুলি ব্যবহার করে একটি প্রশ্নের সাথে কেবল 1 এলডিএপি কল করে AP কেবলমাত্র গ্রুপের নাম ("সিএন" সম্পত্তি) এর চেয়ে বেশি সংখ্যক বৈশিষ্ট্যের প্রয়োজন হলে এটি সহজেই বাড়ানো যেতে পারে।

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

অসাধারণ! ধন্যবাদ। আমি কিছু কোড লেখা শুরু করেছিলাম এবং getAuthorizationGroups ব্যবহার করছিলাম এবং ভীষণ ভয় পেয়ে গিয়েছিল যে সমস্ত গোষ্ঠী পেতে 300ms-2.5s লাগছে। আপনার পদ্ধতিটি 20-30 এমএসে সম্পন্ন হয়।
কিথ

4
এটি আশাব্যঞ্জক বলে মনে হয়েছিল, তবে এটি নেস্টেড গোষ্ঠীগুলি সমাধান করে না, যেমন কোনও ব্যবহারকারী গ্রুপ এ এর ​​সদস্য, যা নিজেই গ্রুপ এক্স এর সদস্য। উপরের কোডটি কেবলমাত্র গ্রুপ এ প্রদর্শিত হবে, তবে গ্রুপ x নয়। : আমি tokenGroups মাধ্যমে এই পদ্ধতি ব্যবহার stackoverflow.com/a/4460658/602449
রবার্ট Muehsig

রবার্ট মুহেসিগের মন্তব্যটি একবার দেখুন - এটি নিস্ট গ্রুপগুলি করে এবং আরও দ্রুত। কেবলমাত্র খারাপ দিক এটি কেবল সুরক্ষা গোষ্ঠীগুলি বিতরণ গ্রুপগুলি নয়
নিক রুবিনো

@ বিগজিম getAuthorizationGroups ব্যবহার করতে পারে না কারণ এটির তথ্য ফিরিয়ে আনতে প্রায় sec সেকেন্ড সময় লাগে তবে আপনার প্রদত্ত কোডটি প্রত্যেকের মতো, ডোমেন ব্যবহারকারীগণ ইত্যাদির মতো সুপরিচিত গ্রুপগুলি ফেরত দেয় না এবং আমার এটি থাকা দরকার। সেখানকার সমস্ত কিছুই কেবল "কাস্টম গোষ্ঠী" প্রত্যাবর্তন করে এবং ব্যবহারকারীর প্রতিটি গ্রুপ নয়।
থিয়েরি

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

আমার ক্ষেত্রে কেবলমাত্র কোনও উপায় ছাড়াই গেটগ্রুপস () ব্যবহার করা চালিয়ে যাওয়া ব্যবহারকারীর (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. "উন্নত" বোতামে ক্লিক করুন Click
  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 - এই সমস্ত সদস্যের মধ্যে এমন সমস্ত অনুমোদন গোষ্ঠী রয়েছে এমন প্রধান অবজেক্টের সংকলন প্রদান করে। এই ফাংশনটি এমন গোষ্ঠীগুলি দেয় যা সুরক্ষা গোষ্ঠী; বিতরণ গ্রুপগুলি ফেরত দেওয়া হয় না।

এই পদ্ধতিটি সমস্ত গ্রুপকে পুনরাবৃত্তভাবে অনুসন্ধান করে এবং সেই গোষ্ঠীগুলিকে ফিরিয়ে দেয় যেখানে ব্যবহারকারী সদস্য is ফিরে আসা সেটে অতিরিক্ত গোষ্ঠীও অন্তর্ভুক্ত থাকতে পারে যা অনুমোদনের উদ্দেশ্যে ব্যবহারকারী ব্যবহারকারীকে সদস্য হিসাবে বিবেচনা করবে।

তাই 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

যদি অনুবাদ স্থানীয়ভাবে কাজ করে তবে দূরবর্তীভাবে ei গ্রুপ নয়।অনুবাদ (typeof (NTAccount)

আপনি যদি অ্যাপ্লিকেশন কোডটি লগড ইন ইউজার পরিচয় ব্যবহার করে কার্যকর করতে চান, তবে ছদ্মবেশটি সক্ষম করুন। আইআইএসের মাধ্যমে বা ওয়েবকনফাইগে নিম্নলিখিত উপাদানগুলি যুক্ত করে ছদ্মবেশ তৈরি করা যায়

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

যদি ছদ্মবেশটি সক্ষম করা থাকে, অ্যাপ্লিকেশনটি আপনার ব্যবহারকারীর অ্যাকাউন্টে পাওয়া অনুমতিগুলি ব্যবহার করে কার্যকর করে। সুতরাং যদি লগ ইন করা ব্যবহারকারীর নির্দিষ্ট নেটওয়ার্ক সংস্থায় অ্যাক্সেস থাকে তবে কেবলমাত্র সে অ্যাপ্লিকেশনটির মাধ্যমে সেই সংস্থানটি অ্যাক্সেস করতে সক্ষম হবে।

তাঁর পরিশ্রমী ভিডিও থেকে এই তথ্যের জন্য PRAGIM প্রযুক্তিকে ধন্যবাদ

উইন্ডোজ প্রমাণীকরণের জন্য As.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

দ্রষ্টব্য: গোষ্ঠীটি অবশ্যই একটি ব্যাকস্ল্যাশ - অর্থাৎ "থিডোমাইন \ দ্যগ্রুপ" দিয়ে লেখা উচিত

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.