Asp.net कोर में वर्तमान उपयोगकर्ता कैसे प्राप्त करें


128

मैं एक वर्तमान उपयोगकर्ता को एक ईमेल जैसे उपयोगकर्ता की जानकारी प्राप्त करना चाहता हूं। लेकिन मैं asp.net कोर में ऐसा नहीं कर सकता। मैं बहुत भ्रमित हूँ यह मेरा कोड है।

HttpContextनियंत्रक के निर्माण में लगभग शून्य है । प्रत्येक क्रिया में उपयोगकर्ता प्राप्त करना अच्छा नहीं है। मैं एक बार उपयोगकर्ता की जानकारी प्राप्त करना और उन्हें सेट करना चाहता हूं ViewData;

public DashboardController()
{
    var user = HttpContext.User.GetUserId();
}

5
MVC या वेब APi के साथ उपयोग करना?
तुषार

जवाबों:


172
User.FindFirst(ClaimTypes.NameIdentifier).Value

निर्माता के लिए ईडीआईटी

नीचे कोड काम करता है:

public Controller(IHttpContextAccessor httpContextAccessor)
{
    var userId = httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value 
}

RTM के लिए संपादित करें

आपको पंजीकरण करना चाहिए IHttpContextAccessor:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpContextAccessor();
    }

2
यह कार्यों में काम करता है। लेकिन मैं नियंत्रक के निर्माण में उपयोग करना चाहता हूं।
मेहरान हाफ़िज़ी

3
क्या कक्षाओं में इसका उपयोग संभव है?
मेहरान हाफ़िज़ी

5
ClaimTypes.NameIdentifierवर्तमान उपयोगकर्ता आईडी ClaimTypes.Nameदेता है , और उपयोगकर्ता नाम देता है।
निकोले कोस्तोव

3
क्या कोई मुझे बता सकता है कि UserPrincipal.Current.Name में क्या गलत है?
टिपुरा

2
@ademcaglin कुछ कारणों से उपयोगकर्ता nullमेरे मामले में वापस आ रहा है? Im .Net core 2.1 Web apiहालांकि का उपयोग कर ।
श्रुति वर्गीस '’

54

सरल तरीका है कि काम करता है और मैंने जाँच की।

private readonly UserManager<IdentityUser> _userManager;
public CompetitionsController(UserManager<IdentityUser> userManager)
{
    _userManager = userManager;
}

var user = await _userManager.GetUserAsync(HttpContext.User);

तो आप इस चर के सभी गुणों को पसंद कर सकते हैं user.Email। मुझे उम्मीद है कि इससे किसी को मदद मिलेगी।

संपादित करें :

यह एक स्पष्ट रूप से सरल बात है, लेकिन ASP.NET कोर में विभिन्न प्रकार के प्रमाणीकरण प्रणालियों का थोड़ा जटिल कारण है। मैं अपडेट करता हूं कि कुछ लोग मिल रहे हैं null

JWT प्रमाणीकरण के लिए (ASP.NET Core v3.0.0-pred7 पर परीक्षण):

var email = HttpContext.User.Claims.FirstOrDefault(c => c.Type == "sub")?.Value;

var user = await _userManager.FindByEmailAsync(email);

1
asp.net Core 2.0 में एक नियंत्रक के अंदर मेरे लिए बहुत अच्छा काम करता है
jmdon

2
एक _उसमर क्या है?
NullVoxPopuli

6
ASP.NET कोर पहचान में, उपयोगकर्ता प्रबंधक उपयोगकर्ताओं को बनाने के लिए निर्भरता इंजेक्शन द्वारा प्रदान की गई सेवा है। अधिक जानकारी के लिए डॉक्स देखें :
अहमद

2
यह गैर-एस्किंस विधि में कैसे प्राप्त किया जा सकता है?
T3.0

मेरे लिए अशक्त लौट रहा है। क्यों?
अल्बर्टो क्लॉडियो मंडलेट

22

Asp.net Core में वर्तमान उपयोगकर्ता प्राप्त करने का एक और तरीका है - और मुझे लगता है कि मैंने इसे कहीं और देखा, तो SO ^ ^ पर

// Stores UserManager
private readonly UserManager<ApplicationUser> _manager; 

// Inject UserManager using dependency injection.
// Works only if you choose "Individual user accounts" during project creation.
public DemoController(UserManager<ApplicationUser> manager)  
{  
    _manager = manager;  
}

// You can also just take part after return and use it in async methods.
private async Task<ApplicationUser> GetCurrentUser()  
{  
    return await _manager.GetUserAsync(HttpContext.User);  
}  

// Generic demo method.
public async Task DemoMethod()  
{  
    var user = await GetCurrentUser(); 
    string userEmail = user.Email; // Here you gets user email 
    string userId = user.Id;
}  

वह कोड DemoController नाम के कंट्रोलर के पास जाता है। इंतजार किए बिना दोनों काम नहीं करेंगे (संकलन नहीं करेंगे;);


इसके लिए पहचान की आवश्यकता होती है
Fraze

1
ApplicationUser क्या है?
माइक

ApplicationUser को आमतौर पर IdentityUser से विरासत में प्राप्त किया जाता है ताकि इसे अतिरिक्त गुणों के साथ बढ़ाया जा सके, आदि
Corgalore

20

मुझे कहना है कि मुझे काफी आश्चर्य हुआ कि कंस्ट्रक्टर के अंदर HttpContext शून्य है। मुझे यकीन है कि यह प्रदर्शन कारणों से है। पुष्टि की है कि IPrincipalनीचे वर्णित के रूप में उपयोग करने से यह कंस्ट्रक्टर में अंतःक्षिप्त हो जाता है। यह अनिवार्य रूप से स्वीकार किए जाते हैं उत्तर के रूप में ही कर रहे हैं, लेकिन एक अधिक स्पष्ट तरीके से।


किसी के लिए भी यह सवाल जेनेरिक के जवाब की तलाश में है "वर्तमान उपयोगकर्ता कैसे प्राप्त करें?" आप बस Userसे सीधे पहुँच सकते हैं Controller.User। लेकिन आप इसे केवल एक्शन विधियों के अंदर ही कर सकते हैं (मेरा मानना ​​है कि नियंत्रक केवल HttpContexts और प्रदर्शन कारणों से नहीं चलते हैं)।

हालाँकि - यदि आपको कंस्ट्रक्टर में इसकी आवश्यकता है (जैसा कि ओपी ने किया था) या अन्य इंजेक्टेबल ऑब्जेक्ट बनाने की आवश्यकता है जो वर्तमान उपयोगकर्ता की आवश्यकता है तो नीचे एक बेहतर तरीका है:

उपयोगकर्ता प्राप्त करने के लिए IPrincipal इंजेक्षन

पहले मिलते हैं IPrincipalऔरIIdentity

public interface IPrincipal
{
    IIdentity Identity { get; }
    bool IsInRole(string role);
}

public interface IIdentity
{
    string AuthenticationType { get; }
    bool IsAuthenticated { get; }
    string Name { get; }
}

IPrincipalऔर IIdentityउपयोगकर्ता और उपयोगकर्ता नाम का प्रतिनिधित्व करता है। अगर al प्रिंसिपल ’अजीब लगे तो विकिपीडिया आपको सुकून देगा

यह महसूस करना महत्वपूर्ण है कि क्या आप इसे प्राप्त करते हैं IHttpContextAccessor.HttpContext.User, ControllerBase.Userया ControllerBase.HttpContext.Userआपको एक ऐसी वस्तु मिल रही है जिसकी गारंटी एक ऐसी ClaimsPrincipalवस्तु है जो लागू होती हैIPrincipal

कोई अन्य प्रकार का उपयोगकर्ता नहीं है जो ASP.NET Userअभी उपयोग करता है , (लेकिन ऐसा नहीं है कि कुछ और कहें जो लागू नहीं हो सका IPrincipal)।

इसलिए यदि आपके पास कोई ऐसी चीज है जिस पर 'वर्तमान उपयोगकर्ता नाम' की निर्भरता है जिसे आप इंजेक्ट करना चाहते हैं तो आपको इंजेक्शन लगाना चाहिए IPrincipalऔर निश्चित रूप से नहीं IHttpContextAccessor

महत्वपूर्ण:IPrincipal सीधे अपने नियंत्रक, या एक्शन विधि पर इंजेक्शन लगाने में समय बर्बाद न करें - यह तब से बेकार है जब Userसे आप पहले से ही वहां उपलब्ध हैं।

इन startup.cs:

   // Inject IPrincipal
   services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);

फिर आपके DI ऑब्जेक्ट में उस उपयोगकर्ता की आवश्यकता है जिसे आप IPrincipalवर्तमान उपयोगकर्ता प्राप्त करने के लिए इंजेक्ट करते हैं।

यहां सबसे महत्वपूर्ण बात यह है कि यदि आप यूनिट टेस्ट कर रहे हैं तो आपको भेजने की आवश्यकता नहीं है HttpContext, लेकिन केवल कुछ का मजाक उड़ाने की जरूरत है जो प्रतिनिधित्व करता है IPrincipal जो अभी हो सकता है ClaimsPrincipal

एक अतिरिक्त महत्वपूर्ण बात जो मैं 100% सुनिश्चित नहीं हूं। यदि आपको वास्तविक दावों तक पहुंचने की आवश्यकता है, तो आपको ClaimsPrincipalकास्ट IPrincipalकरने की आवश्यकता है ClaimsPrincipal। यह ठीक है क्योंकि हम 100% जानते हैं कि रनटाइम में यह उस प्रकार का है (क्योंकि यही HttpContext.Userहै)। मैं वास्तव में कंस्ट्रक्टर में ऐसा करना पसंद करता हूं क्योंकि मुझे पहले से ही पता है कि कोई भी IPrincipal होगा ClaimsPrincipal

यदि आप मॉकिंग कर रहे हैं, तो बस एक ClaimsPrincipalसीधा बनाएं और जो भी लेता है उसे पास करें IPrincipal

वास्तव में, IClaimsPrincipalमुझे यकीन नहीं है के लिए कोई इंटरफ़ेस नहीं है। मुझे लगता है कि एमएस ने फैसला किया कि ClaimsPrincipalसिर्फ एक विशेष 'संग्रह' था जो एक इंटरफ़ेस को वारंट नहीं करता था।


2
यह आपको अपने आवेदन में कहीं भी वर्तमान उपयोगकर्ता को इंजेक्ट करने की अनुमति देता है, शानदार जवाब!
मचाडो

1
यह काम नहीं करता है। मैं हमेशा nullइंजेक्शन के लिए मिलता हूं IPrincipal। मुझे क्षणिक सेवा को …GetService<IHttpContextAccessor>()?.HttpContext.User…(के साथ ?) जोड़ने की भी आवश्यकता थी क्योंकि यह अन्यथा दुर्घटनाग्रस्त हो जाती (गेट्सवेयर्स वापस लौट आती है)।
1919

आप बस के services.AddTransient(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);रूप में कर सकते हैं HttpContext.User एक ClaimsPrincipal है।
जे ज़ेलोस

18

ऐसा प्रतीत होता है कि अब (2017 के अप्रैल से) निम्नलिखित कार्य करता है:

public string LoggedInUser => User.Identity.Name;

कम से कम जबकि भीतर Controller


4
आप 'System.Security.Principal.IIdentity' प्रकार को 'स्ट्रिंग' में नहीं बदल सकते।
एंथनी हुआंग

3
string LogInUser = User.Identity.Name;
एलिक डब्ल्यू सिप

5
जैसा कि किसी ने =>पहले इस तरह इस्तेमाल किए गए ऑपरेटर को नहीं देखा था , इसे "एक्सप्रेशन बॉडी डेफिनिशन" कहा जाता है और इस प्रलेखन में वर्णित है । बस भविष्य में मेरे जैसे लोग आश्चर्यचकित हैं।
नाथन क्लेमेंट

आपका कोड संभवतः संपादन से पहले संकलित नहीं कर सकता है, यह देखते हुए कि इससे कोई रूपांतरण नहीं IIdentityहै string, जैसा कि शीर्ष टिप्पणी में भी कहा गया है। संपादित बस तय है कि। मुझे यकीन नहीं है कि आप अपने निष्कर्ष पर कैसे पहुंचे (विशेष रूप से "संपादक" अंक केवल 2k प्रतिष्ठा से नीचे के उपयोगकर्ताओं को दिए गए हैं)।
fuglede

9

शायद मुझे इसका जवाब नहीं मिला, लेकिन मैं ऐसा करता हूं।

  1. .Net कोर -> गुण -> लॉन्चसैटिंग.जॉन

आपको इन मूल्यों को बदलना होगा

"windowsAuthentication": true, // needs to be true
"anonymousAuthentication": false,  // needs to be false 

Startup.cs -> कॉन्फ़िगर सेवाएँ (...)

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

MVC या वेब एपीआई नियंत्रक

private readonly IHttpContextAccessor _httpContextAccessor;
//constructor then
_httpContextAccessor = httpContextAccessor;

नियंत्रक विधि:

string userName = _httpContextAccessor.HttpContext.User.Identity.Name;

परिणाम उपयोगकर्ता नाम है जैसे = डोमेन \ उपयोगकर्ता नाम


4

मेरी समस्या cshtml फ़ाइल में एक ऑब्जेक्ट के रूप में उपयोगकर्ता को लॉग इन करने की थी। ViewData में उपयोगकर्ता को ध्यान में रखते हुए, यह दृष्टिकोण सहायक हो सकता है:

Cshtml फ़ाइल में

@using Microsoft.AspNetCore.Identity
@inject UserManager<ApplicationUser> UserManager

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>
    @UserManager.FindByNameAsync(UserManager.GetUserName(User)).Result.Email
    </title>
  </head>
  <body>

  </body>
</html>

किसी भी विचार को लोड करने के लिए आपको कैसे एक नेविगेशन संपत्ति मिल सकती है (कंपनी का एप्लिकेशन नेवीगेशन प्रॉपर्टी का नाम मेरे ApplicationUser वर्ग पर)। नेविगेशन गुणों को शामिल करने का एक तरीका नहीं देखा।
हंटर नेल्सन

1

मौजूदा उत्तरों के अलावा, मैं यह जोड़ना चाहूंगा कि आपके पास एक वर्ग का उदाहरण उपलब्ध ऐप-वाइड भी हो सकता है जो उपयोगकर्ता से संबंधित डेटा को रखता है जैसे UserIDआदि।

यह रिफैक्टरिंग के लिए उपयोगी हो सकता है । आप UserIDप्रत्येक कंट्रोलर एक्शन में नहीं आना चाहते हैं और UserIDसर्विस लेयर से संबंधित प्रत्येक विधि में एक अतिरिक्त पैरामीटर घोषित कर सकते हैं ।

मैंने एक शोध किया है और यहाँ मेरी पोस्ट है

आप बस अपने वर्ग का विस्तार करते हैं जिसे आप संपत्ति DbContextजोड़कर प्राप्त करते UserIdहैं (या एक कस्टम Sessionवर्ग लागू करते हैं जिसके पास यह संपत्ति है)।

फ़िल्टर स्तर पर आप अपने वर्ग का उदाहरण प्राप्त कर सकते हैं और UserIdमूल्य निर्धारित कर सकते हैं ।

उसके बाद जहां भी आप अपने उदाहरण को इंजेक्ट करते हैं - उसके पास आवश्यक डेटा होगा (आजीवन अनुरोध के अनुसार होना चाहिए , इसलिए आप इसे AddScopedविधि का उपयोग करके पंजीकृत करते हैं )।

कार्य उदाहरण:

public class AppInitializationFilter : IAsyncActionFilter
{
    private DBContextWithUserAuditing _dbContext;

    public AppInitializationFilter(
        DBContextWithUserAuditing dbContext
        )
    {
        _dbContext = dbContext;
    }

    public async Task OnActionExecutionAsync(
        ActionExecutingContext context,
        ActionExecutionDelegate next
        )
    {
        string userId = null;
        int? tenantId = null;

        var claimsIdentity = (ClaimsIdentity)context.HttpContext.User.Identity;

        var userIdClaim = claimsIdentity.Claims.SingleOrDefault(c => c.Type == ClaimTypes.NameIdentifier);
        if (userIdClaim != null)
        {
            userId = userIdClaim.Value;
        }

        var tenantIdClaim = claimsIdentity.Claims.SingleOrDefault(c => c.Type == CustomClaims.TenantId);
        if (tenantIdClaim != null)
        {
            tenantId = !string.IsNullOrEmpty(tenantIdClaim.Value) ? int.Parse(tenantIdClaim.Value) : (int?)null;
        }

        _dbContext.UserId = userId;
        _dbContext.TenantId = tenantId;

        var resultContext = await next();
    }
}

अधिक जानकारी के लिए मेरा उत्तर देखें ।


0

लेना IdentityUserभी काम होगा। यह एक वर्तमान उपयोगकर्ता ऑब्जेक्ट है और उपयोगकर्ता के सभी मूल्यों को पुनर्प्राप्त किया जा सकता है।

private readonly UserManager<IdentityUser> _userManager;
public yourController(UserManager<IdentityUser> userManager)
{
    _userManager = userManager;
}

var user = await _userManager.GetUserAsync(HttpContext.User);

0

यदि आप स्कैफोल्ड आईडेंटिटी का उपयोग कर रहे हैं और Asp.net Core 2.2+ का उपयोग कर रहे हैं, तो आप वर्तमान उपयोगकर्ता को इस तरह से देख सकते हैं:

@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager

 @if (SignInManager.IsSignedIn(User))
    {
        <p>Hello @User.Identity.Name!</p>
    }
    else
    {
        <p>You're not signed in!</p>
    }

https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-2.2&tabs=visual-studio


0

यह पुराना सवाल है लेकिन मेरा मामला दिखाता है कि मेरे मामले की यहां चर्चा नहीं की गई।

मुझे साइमन_वेवर ( https://stackoverflow.com/a/54411397/2903893 ) का उत्तर सबसे अधिक पसंद है । वह विवरण में बताते हैं कि IPrincipal और IIdentity का उपयोग करके उपयोगकर्ता नाम कैसे प्राप्त करें। यह उत्तर बिल्कुल सही है और मैं इस दृष्टिकोण का उपयोग करने की सलाह देता हूं। हालाँकि, डिबगिंग के दौरान मुझे समस्या का सामना करना पड़ा जब ASP.NET सेवा सिद्धांत को ठीक से नहीं कर सकता है । (या दूसरे शब्दों में, IPrincipal.Identity.Name शून्य है)

यह स्पष्ट है कि उपयोगकर्ता नाम MVC फ्रेमवर्क प्राप्त करने के लिए इसे कहीं से लेना चाहिए। .NET की दुनिया में ASP.NET या ASP.NET Core ओपन आईडी कनेक्ट मिडलवेयर का उपयोग कर रहे हैं। सरल परिदृश्य में वेब ऐप उपयोगकर्ता को वेब ब्राउज़र में प्रमाणित करते हैं। इस परिदृश्य में, वेब अनुप्रयोग उपयोगकर्ता के ब्राउज़र को उन्हें Azure AD में साइन इन करने का निर्देश देता है। Azure AD उपयोगकर्ता के ब्राउज़र के माध्यम से साइन-इन प्रतिक्रिया देता है, जिसमें सुरक्षा टोकन में उपयोगकर्ता के बारे में दावे होते हैं। अपने एप्लिकेशन के लिए इसे कोड में काम करने के लिए, आपको वह अधिकार प्रदान करना होगा, जिसके लिए आप वेब ऐप साइन-इन का प्रतिनिधित्व करते हैं। जब आप अपने वेब ऐप को Azure Service में तैनात करते हैं, तो इस आवश्यकता को पूरा करने के लिए सामान्य परिदृश्य वेब ऐप को कॉन्फ़िगर करना है: "ऐप सेवाएँ" -> YourApp -> "प्रमाणीकरण / प्राधिकरण" ब्लेड -> "ऐप सेवा प्रामाणिकता =" "ऑन"https://github.com/Huachao/azure-content/blob/master/articles/app-service-api/app-service-ap-authentication.md )। मैं विश्वास करता हूं (यह मेरा शिक्षित अनुमान है) कि इस प्रक्रिया के हुड के तहत विज़ार्ड उसी वेब ऐप के "माता-पिता" वेब कॉन्फ़िगरेशन को समायोजित करता है, जो कि मैं निम्नलिखित पैराग्राफ में दिखाता हूं। असल में, यह मुद्दा ASP.NET कोर में काम क्यों नहीं करता है, क्योंकि "पैरेंट" मशीन कॉन्फिग को webconfig द्वारा अनदेखा किया जाता है। (यह 100% निश्चित नहीं है, मैं अभी सबसे अच्छा स्पष्टीकरण देता हूं जो मेरे पास है)। इसलिए, यह काम करने के लिए आपको इसे अपने ऐप में मैन्युअल रूप से सेटअप करने की आवश्यकता है।

यहां एक लेख है जो बताता है कि Azure AD का उपयोग करने के लिए अपने ऐप को कितने सेटअप करना है। https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/aspnetcore2-2

चरण 1: अपने एज़्योर एडी किरायेदार के साथ नमूना पंजीकृत करें। (यह स्पष्ट है, स्पष्टीकरण के मेरे समय खर्च नहीं करना चाहते हैं)।

चरण 2: appsettings.json फ़ाइल में: आपके द्वारा आवेदन पंजीकरण पोर्टल में पंजीकृत आवेदन से IDID के साथ ClientID मान को बदलें। चरण 1 में TenantId मान को आम के साथ बदलें

चरण 3: Startup.cs फ़ाइल खोलें और कन्फ़िगरसर्विस विधि में, जिसमें लाइन सम्‍मिलित है। AddAzureAD में निम्‍न कोड डालें, जो आपके एप्लिकेशन को Azure AD v2.0 समापन बिंदु वाले उपयोगकर्ताओं में साइन इन करने में सक्षम बनाता है, जो कार्य और विद्यालय और दोनों हैं Microsoft व्यक्तिगत खाते।

services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
    options.Authority = options.Authority + "/v2.0/";
    options.TokenValidationParameters.ValidateIssuer = false;
});

सारांश : मैंने एक और संभावित मुद्दा दिखाया है जो कि विषय स्टार्टर को समझाया गया है एक त्रुटि के कारण हो सकता है। इस समस्या का कारण एज़्योर एडी (ओपन आईडी मिडलवेयर) के लिए अनुपलब्ध कॉन्फ़िगरेशन है। इस समस्या को हल करने के लिए मैं मैन्युअल रूप से "प्रमाणीकरण / प्राधिकरण" सेटअप का प्रस्ताव करता हूं। इसे सेटअप करने के तरीके का संक्षिप्त अवलोकन जोड़ा गया है।


0

अधिकांश उत्तर बताते हैं कि HttpContextप्रलेखन से सबसे अच्छा कैसे संभालना है, जो कि मैं भी गया था।

मैं यह उल्लेख करना चाहता था कि डिबगिंग करते समय आप प्रोजेक्ट सेटिंग्स की जांच करना चाहते हैं, डिफ़ॉल्ट है Enable Anonymous Authentication = true


-1

मुझे मेरा हल मिल गया

var claim = HttpContext.User.CurrentUserID();

public static class XYZ
{
    public static int CurrentUserID(this ClaimsPrincipal claim)
    {
        var userID = claimsPrincipal.Claims.ToList().Find(r => r.Type == 
         "UserID").Value;
        return Convert.ToInt32(userID);
    }
    public static string CurrentUserRole(this ClaimsPrincipal claim)
    {
        var role = claimsPrincipal.Claims.ToList().Find(r => r.Type == 
        "Role").Value;
        return role;
    }
}

1
इस कोड को इस सवाल का जवाब कर सकते हैं, के बारे में अतिरिक्त संदर्भ प्रदान करने के लिए कैसे और क्यों यह हल करती है समस्या जवाब की दीर्घकालिक मूल्य में सुधार होगा।
अलेक्जेंडर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.