User.Identity के उपलब्ध गुणों का विस्तार कैसे करें


130

मैं अपनी वेबसाइट में लॉग इन करने के लिए उपयोगकर्ताओं के लिए MVC5 पहचान 2.0 का उपयोग कर रहा हूं, जहां एक एसक्यूएल डेटाबेस में प्रमाणीकरण विवरण संग्रहीत हैं। Asp.net पहचान को एक मानक तरीके से लागू किया गया है जैसा कि कई ऑनलाइन ट्यूटोरियल में पाया जा सकता है।

IdentityModels में ApplicationUser वर्ग को कुछ कस्टम गुणों को शामिल करने के लिए बढ़ाया गया है, जैसे कि पूर्णांक ऑर्गनाइजेशन। विचार यह है कि कई उपयोगकर्ताओं को डेटाबेस संबंध प्रयोजनों के लिए एक सामान्य संगठन को बनाया और सौंपा जा सकता है।

public class ApplicationUser : IdentityUser
    {
        public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
        {
            // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
            // Add custom user claims here
            return userIdentity;
        }

        //Extended Properties
        public DateTime? BirthDate { get; set; }
        public long? OrganizationId { get; set; }

        //Key Mappings
        [ForeignKey("OrganizationId")]
        public virtual Organization Organization { get; set; }
    }

मैं वर्तमान में एक नियंत्रक के भीतर से उपयोगकर्ता में लॉग इन की OrganIIII संपत्ति कैसे प्राप्त कर सकता हूं? क्या उपयोगकर्ता द्वारा लॉग इन करने के बाद यह विधि के माध्यम से उपलब्ध है या क्या मुझे हमेशा यूजरआईड के आधार पर, डेटाबेस से ऑर्गनाइजेशन को पुनः प्राप्त करना होता है, हर बार एक नियंत्रक विधि निष्पादित होती है?

वेब पर चारों ओर पढ़ना मैंने देखा है कि मुझे उपयोगकर्ता आईडी आदि में लॉग इन करने के लिए निम्नलिखित का उपयोग करने की आवश्यकता है।

using Microsoft.AspNet.Identity;
...
User.Identity.GetUserId();

हालाँकि, OrganizationId User.Identity में उपलब्ध संपत्ति नहीं है। क्या मुझे OrganizationId संपत्ति को शामिल करने के लिए User.Identity का विस्तार करने की आवश्यकता है? यदि हां, तो मैं इस बारे में कैसे जाऊंगा।

इसका कारण यह है कि मुझे अक्सर इस संगठन की आवश्यकता है कि कई तालिका क्वेरीज़ संगठन से संबंधित डेटा को पुनः प्राप्त करने के लिए OrganId पर निर्भर हैं जो उपयोगकर्ता में लॉग इन से जुड़ी है।


3
क्या मेरा जवाब यहाँ आपकी मदद करता है ?
जूता

1
मेरे यहाँ से बहुत ही समान उत्तर: stackoverflow.com/a/28138594/809357 - यदि आपको अनुरोध के जीवन में नियमित रूप से इस जानकारी की आवश्यकता है, तो आप इसे एक दावे के रूप में कुकी पर रख सकते हैं।
ट्रेलमैक्स

1
धन्यवाद @ शोहे आपके दोनों जवाब काम कर गए। आपके उत्तरों के अतिरिक्त, मुझे कुकी में संग्रहीत होने का दावा भी जोड़ना था। IdentityModels वर्ग में मुझे userIdentity.AddClaim (नया दावा ("MyApp: OrganizationId", OrganizationId.ToString ())) जोड़ना था ; करने के लिए सार्वजनिक async टास्क <ClaimsIdentity> GenerateUserIdentityAsync (UserManager <ApplicationUser> प्रबंधक) विधि।
रॉबर्ड 28

जवाबों:


219

जब भी आप उपर्युक्त प्रश्न जैसे किसी अतिरिक्त गुण के साथ User.Identity के गुणों का विस्तार करना चाहते हैं, तो इन गुणों को पहले ApplicationUser वर्ग में जोड़ें:

public class ApplicationUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        return userIdentity;
    }

    // Your Extended Properties
    public long? OrganizationId { get; set; }
}

फिर आपको एक एक्सटेंशन विधि बनाने की आवश्यकता है, जैसे (मैं एक नए एक्सटेंशन फ़ोल्डर में मेरा निर्माण करता हूं):

namespace App.Extensions
{
    public static class IdentityExtensions
    {
        public static string GetOrganizationId(this IIdentity identity)
        {
            var claim = ((ClaimsIdentity)identity).FindFirst("OrganizationId");
            // Test for null to avoid issues during local testing
            return (claim != null) ? claim.Value : string.Empty;
        }
    }
}

जब आप ApplicationUser वर्ग में पहचान बनाते हैं, तो केवल दावा जोड़ें -> OrganizationId जैसे:

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here => this.OrganizationId is a value stored in database against the user
        userIdentity.AddClaim(new Claim("OrganizationId", this.OrganizationId.ToString()));

        return userIdentity;
    }

एक बार जब आप दावा जोड़ लेते हैं और आपके पास अपनी एक्सटेंशन विधि होती है, तो इसे अपने User.Identity पर एक संपत्ति के रूप में उपलब्ध कराने के लिए, उस पृष्ठ / फ़ाइल पर एक उपयोग कथन जोड़ें जिसे आप इसे एक्सेस करना चाहते हैं :

मेरे मामले में: using App.Extensions;एक नियंत्रक के @using. App.Extensionsभीतर और एक .cshtml देखें फ़ाइल के साथ।

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

प्रत्येक दृश्य में एक उपयोग कथन जोड़ने से बचने के लिए आप क्या कर सकते हैं, दृश्य फ़ोल्डर में जाना है, और वहां Web.config फ़ाइल का पता लगाना है। अब <namespaces>टैग को देखें और अपने एक्सटेंशन नामस्थान को इस तरह जोड़ें:

<add namespace="App.Extensions" />

अपनी फ़ाइल सहेजें और आपका काम हो गया। अब हर View को आपके एक्सटेंशन का पता चल जाएगा।

आप एक्सटेंशन विधि तक पहुँच सकते हैं:

var orgId = User.Identity.GetOrganizationId();

हाय pawel, मैंने भी यही कोशिश की है, लेकिन त्रुटि हो रही है कि अनुप्रयोग उपयोगकर्ता में OrganisationId की परिभाषा शामिल नहीं है
यह

@ रचितगुप्ता यह कब होता है? जब आप दावे को जोड़ने की कोशिश कर रहे हों या जब आप बाद में कोड में इसके मूल्य तक पहुंचने की कोशिश कर रहे हों? यदि ऐसा हो जब आप कोई दावा जोड़ रहे हों, तो सुनिश्चित करें कि आपके ApplicationUser में संपत्ति परिभाषित है ... यदि यह बाद में कोड में है तो आप उस विवरण को जोड़ना न भूलें जहां आपने एक्सटेंशन विधि बनाई है: App का उपयोग करके। ;
पावेल

UserIdentity.AddClaim लाइन में त्रुटि मिली। मैंने IdentityMxtels.cs फ़ाइल में केवल IdentityExtension वर्ग बनाया है। क्या यह समस्या का स्रोत हो सकता है?
यह

नहींं, अगर यह दावा है कि आप इसे जोड़ते हैं, तो इससे पहले कि यह होता है कि पहचान में आने से पहले यह होता है सार्वजनिक लंबे संगठनआईडीआई {प्राप्त करें; सेट; }
पावेल

6
धन्यवाद, यह काम किया। मुझे लगता है कि एस्प नेट आइडेंडिटी 2 में कस्टम चर के लिए यह सबसे अच्छा अभ्यास है। मुझे नहीं पता कि Asp.Net समुदाय अपनी वेबसाइटों पर डिफ़ॉल्ट लेखों में ऐसा उदाहरण क्यों नहीं प्रदान करता है।
OneNiceFriend

17

मैं उसी समाधान की तलाश में था और पावेल ने मुझे 99% उत्तर दिया। केवल एक चीज जो गायब थी जिसे मुझे प्रदर्शित करने के लिए एक्सटेंशन की आवश्यकता थी वह निम्नलिखित रेजर कोड को cshtml में जोड़ रहा था (देखें) पृष्ठ:

@using programname.Models.Extensions

उपयोगकर्ता के लॉग इन के बाद मैं अपने नवबेर के शीर्ष दाईं ओर प्रदर्शित करने के लिए FirstName की तलाश कर रहा था।

मैंने सोचा कि मैं इस घटना को किसी और की मदद करता हूं, इसलिए यहां मेरा कोड है:

मैंने एक्सटेंशन्स (मेरे मॉडल फ़ोल्डर के तहत) नामक एक नया फ़ोल्डर बनाया और ऊपर निर्दिष्ट पावेल के रूप में नया वर्ग बनाया: IdentityExtensions.cs

using System.Security.Claims;
using System.Security.Principal;

namespace ProgramName.Models.Extensions
{
    public static class IdentityExtensions
    {
        public static string GetUserFirstname(this IIdentity identity)
        {
            var claim = ((ClaimsIdentity)identity).FindFirst("FirstName");
            // Test for null to avoid issues during local testing
            return (claim != null) ? claim.Value : string.Empty;
        }
    }
}

IdentityModels.cs :

public class ApplicationUser : IdentityUser
{

    //Extended Properties
    public string FirstName { get; internal set; }
    public string Surname { get; internal set; }
    public bool isAuthorized { get; set; }
    public bool isActive { get; set; }

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        userIdentity.AddClaim(new Claim("FirstName", this.FirstName));

        return userIdentity;
    }
}

फिर मेरे _LoginPartial.cshtml( Views/Sharedफोल्डर्स के तहत ) मैंने जोड़ा@using.ProgramName.Models.Extensions

मैंने तब कोड की फ़ोलिंग लाइन में परिवर्तन जोड़ा जो लॉग इन करने के बाद उपयोगकर्ताओं के पहले नाम का उपयोग करने वाला था:

@Html.ActionLink("Hello " + User.Identity.GetUserFirstname() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })

शायद यह किसी और को लाइन में मदद करता है।


11

जॉन एटन द्वारा इस महान ब्लॉग पोस्ट की जाँच करें: ASP.NET पहचान 2.0: उपयोगकर्ता और भूमिका को अनुकूलित करना

इस पूरी प्रक्रिया पर चरण-दर-चरण जानकारी बहुत अच्छी है। इसे पढ़ें:)

यहाँ कुछ मूल बातें हैं।

नए गुणों को जोड़कर डिफ़ॉल्ट ApplicationUser वर्ग का विस्तार करें (जैसे- पता, शहर, राज्य, आदि):

public class ApplicationUser : IdentityUser
{
    public async Task<ClaimsIdentity> 
    GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        var userIdentity = await manager.CreateIdentityAsync(this,  DefaultAuthenticationTypes.ApplicationCookie);
        return userIdentity;
    }
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }

    // Use a sensible display name for views:
    [Display(Name = "Postal Code")]
    public string PostalCode { get; set; }

    // Concatenate the address info for display in tables and such:
    public string DisplayAddress
    {
        get
        {
            string dspAddress = string.IsNullOrWhiteSpace(this.Address) ? "" : this.Address;
            string dspCity = string.IsNullOrWhiteSpace(this.City) ? "" : this.City;
            string dspState = string.IsNullOrWhiteSpace(this.State) ? "" : this.State;
            string dspPostalCode = string.IsNullOrWhiteSpace(this.PostalCode) ? "" : this.PostalCode;

            return string.Format("{0} {1} {2} {3}", dspAddress, dspCity, dspState, dspPostalCode);
        }
    }

फिर आप अपने नए गुणों को अपने RegisterViewModel में जोड़ें।

    // Add the new address properties:
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }

फिर नई संपत्तियों को शामिल करने के लिए रजिस्टर दृश्य को अपडेट करें।

    <div class="form-group">
        @Html.LabelFor(m => m.Address, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.Address, new { @class = "form-control" })
        </div>
    </div>

फिर नए गुणों के साथ अकाउंटकंट्रोलर पर रजिस्टर () विधि को अपडेट करें।

    // Add the Address properties:
    user.Address = model.Address;
    user.City = model.City;
    user.State = model.State;
    user.PostalCode = model.PostalCode;

16
यह अच्छा उदाहरण है, लेकिन यह इस सवाल का जवाब नहीं देता है कि आप User.Identity से उन नए गुणों को कैसे प्राप्त करते हैं।
देजन बोगतिनोवस्की

5
डाउनवोट किया गया क्योंकि उत्तर यह नहीं दिखाता है कि कैसे कस्टम गुणों को User.Identity से पुनर्प्राप्त किया जा सकता है।
मौलिक १३

3

ASP.NET Core 2.1 में कस्टम प्रॉपर्टी को एक्सेस करने के तरीके की तलाश करने वाले किसी भी व्यक्ति के लिए - यह बहुत आसान है: आपके पास एक UserManager होगा, जैसे कि _LoginPartial.cshtml में, और फिर आप बस कर सकते हैं (मानकर "ScreenName" संपत्ति जो आपने अपने AppUser में जोड़ी है जो IdentityUser से विरासत में मिली है):

@using Microsoft.AspNetCore.Identity

@using <namespaceWhereYouHaveYourAppUser>

@inject SignInManager<AppUser> SignInManager
@inject UserManager<AppUser> UserManager

@if (SignInManager.IsSignedIn(User)) {
    <form asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="@Url.Action("Index", "Home", new { area = "" })" 
          method="post" id="logoutForm" 
          class="form-inline my-2 my-lg-0">

        <ul class="nav navbar-nav ml-auto">
            <li class="nav-item">
                <a class="nav-link" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">
                    Hello @((await UserManager.GetUserAsync(User)).ScreenName)!
                    <!-- Original code, shows Email-Address: @UserManager.GetUserName(User)! -->
                </a>
            </li>
            <li class="nav-item">
                <button type="submit" class="btn btn-link nav-item navbar-link nav-link">Logout</button>
            </li>
        </ul>

    </form>
} else {
    <ul class="navbar-nav ml-auto">
        <li class="nav-item"><a class="nav-link" asp-area="Identity" asp-page="/Account/Register">Register</a></li>
        <li class="nav-item"><a class="nav-link" asp-area="Identity" asp-page="/Account/Login">Login</a></li>
    </ul>
}

2
यह ध्यान दिया जाना चाहिए कि GetUserAsync(User)संगठन को पुनर्प्राप्त करने के लिए डेटाबेस को क्वेरी करेगा। इसके विपरीत, स्वीकृत समाधान दावों में संगठन (जैसे कुकी) शामिल होंगे। डेटाबेस से इस जानकारी को खींचने का फायदा यह है कि लोगों को लॉगआउट / लॉगिन करने की आवश्यकता के बिना संगठनों के बीच स्थानांतरित किया जा सकता है। बेशक, नुकसान यह है कि इसके लिए एक अतिरिक्त डेटाबेस क्वेरी की आवश्यकता है।
मैट

1

ड्राफ्ट, ApplicationUser वर्ग में संपत्ति जोड़ने का एक अच्छा तरीका देता है। ओपी कोड को देखते हुए ऐसा प्रतीत होता है कि उन्होंने ऐसा किया होगा या ऐसा करने के लिए ट्रैक पर थे। सवाल पूछता है

मैं वर्तमान में एक नियंत्रक के भीतर से उपयोगकर्ता में लॉग इन की OrganIIII संपत्ति कैसे प्राप्त कर सकता हूं? हालाँकि, OrganizationId User.Identity में उपलब्ध संपत्ति नहीं है। क्या मुझे OrganizationId संपत्ति को शामिल करने के लिए User.Identity का विस्तार करने की आवश्यकता है?

पावेल एक विस्तार विधि जोड़ने का एक तरीका देता है जिसमें बयानों का उपयोग करने या वेब.कॉन्फ़िग फ़ाइल में नामस्थान जोड़ने की आवश्यकता होती है।

हालाँकि, सवाल पूछता है कि क्या आपको नई संपत्ति को शामिल करने के लिए User.Identity को "बढ़ाने" की आवश्यकता है। User.Identity का विस्तार किए बिना संपत्ति तक पहुंचने का एक वैकल्पिक तरीका है। यदि आपने ड्राफ्ट विधि का पालन किया है तो आप नई संपत्ति तक पहुंचने के लिए अपने नियंत्रक में निम्न कोड का उपयोग कर सकते हैं।

ApplicationDbContext db = new ApplicationDbContext();
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
var currentUser = manager.FindById(User.Identity.GetUserId());
var myNewProperty = currentUser.OrganizationId;

0

मैंने अपने AspNetUsers तालिका में अतिरिक्त कॉलम भी जोड़े या बढ़ाए हैं। जब मैं केवल इस डेटा को देखना चाहता था, तो मुझे "एक्सटेंशन" आदि के साथ ऊपर दिए गए कोड जैसे कई उदाहरण मिले ... यह वास्तव में मुझे आश्चर्यचकित कर गया कि आपको वर्तमान उपयोगकर्ताओं से कुछ मूल्यों को प्राप्त करने के लिए कोड की उन सभी पंक्तियों को लिखना होगा।

यह पता चला है कि आप किसी अन्य तालिका की तरह AspNetUsers तालिका को क्वेरी कर सकते हैं:

 ApplicationDbContext db = new ApplicationDbContext();
 var user = db.Users.Where(x => x.UserName == User.Identity.Name).FirstOrDefault();
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.