Kullanılabilir User.Identity özellikleri nasıl genişletilir


130

Kullanıcıların web sitemde oturum açması için MVC5 Identity 2.0 kullanıyorum, burada kimlik doğrulama ayrıntıları bir SQL veritabanında depolanıyor. Asp.net Kimliği, birçok çevrimiçi eğiticide bulunabileceği gibi standart bir şekilde uygulanmıştır.

IdentityModels'teki ApplicationUser sınıfı, tamsayı OrganizationId gibi bazı özel özellikleri içerecek şekilde genişletilmiştir. Buradaki fikir, birçok kullanıcının veritabanı ilişkisi amacıyla ortak bir Kuruluşa oluşturulabilmesi ve atanabilmesidir.

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

Şu anda oturum açmış olan kullanıcının OrganizationId özelliğini bir denetleyiciden nasıl alabilirim? Bu, bir kullanıcı oturum açtıktan sonra bir yöntem aracılığıyla kullanılabilir mi, yoksa bir denetleyici yöntemi her yürütüldüğünde, Kullanıcı Kimliğine dayalı olarak Kuruluş Kimliği'ni veritabanından her zaman alabilir miyim?

Web'de okurken Gördüğüm gibi oturum açmış UserId vb. Almak için aşağıdakileri kullanmam gerekiyor.

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

Ancak OrganizationId, User.Identity'de kullanılabilen bir özellik değildir. User.Identity'yi OrganizationId özelliğini içerecek şekilde genişletmem gerekir mi? Eğer öyleyse, bunu nasıl yapacağım?

OrganizationId'ye bu kadar sık ​​ihtiyaç duymamın nedeni, birçok tablo sorgusunun, oturum açmış kullanıcıyla ilişkilendirilmiş Kuruluşla ilgili verileri almak için OrganizationId'ye bağlı olmasıdır.


3
Buradaki cevabım size hiç yardımcı oluyor mu?
Shoe

1
Benden hemen hemen aynı yanıtı burada: stackoverflow.com/a/28138594/809357 - bu bilgilere talebin süresi boyunca düzenli olarak ihtiyaç duyuyorsanız, bunu bir talep olarak tanımlama bilgisine yerleştirebilirsiniz.
trailmax

1
Teşekkürler @Shoe, her iki cevabın da çalıştı Cevaplarınıza ek olarak, çerezde saklanacak bir iddia eklemem gerekiyordu. IdentityModels sınıfında userIdentity.AddClaim (yeni Claim ("MyApp: OrganizationId", OrganizationId.ToString ())); için kamu Görev <ClaimsIdentity> GenerateUserIdentityAsync (UserManager <ApplicationUser> yönetici) zaman uyumsuz yönteminin.
RobHurd

Yanıtlar:


219

User.Identity özelliklerini yukarıdaki soru gibi herhangi bir ek özellik ile genişletmek istediğinizde, bu özellikleri ilk olarak ApplicationUser sınıfına ekleyin:

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

O zaman ihtiyacınız olan şey bunun gibi bir uzantı yöntemi oluşturmaktır (benimkini yeni bir Uzantılar klasöründe oluşturuyorum):

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 sınıfında Kimlik oluşturduğunuzda, Claim -> OrganizationId'yi şu şekilde eklemeniz yeterlidir:

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

Talebi ekledikten ve uzantı yönteminizi yerine getirdikten sonra, bunu User.Identity'nizde bir mülk olarak kullanılabilir hale getirmek için , erişmek istediğiniz sayfaya / dosyaya bir using ifadesi ekleyin :

benim durumumda: using App.Extensions;bir Denetleyici içinde ve @using. App.Extensionsbir .cshtml Görünüm dosyasıyla.

DÜZENLE:

Her Görünümde bir using ifadesi eklemekten kaçınmak için de yapabileceğiniz şey, Görünümler klasörüne gidip oradaki Web.config dosyasını bulmaktır. Şimdi <namespaces>etiketi arayın ve uzantı ad alanınızı şu şekilde ekleyin:

<add namespace="App.Extensions" />

Dosyanızı kaydedin ve bitirdiniz. Artık her Görünüm uzantılarınızı bilecek.

Uzatma Yöntemine erişebilirsiniz:

var orgId = User.Identity.GetOrganizationId();

Merhaba pawel, ben de aynı şeyi denedim, ancak Uygulama kullanıcısının OrganisationId tanımını içermediğine dair hata alıyorum
Bu bir tuzak

@RachitGupta Ne zaman olur? Talebi eklemeye veya daha sonra kodun değerine erişmeye çalıştığınızda? Bir talep eklediğinizde ise, ApplicationUser'ınızın tanımlanmış özelliğe sahip olduğundan emin olun ... Kodda daha sonra ise, using ifadesini şu gibi uzantı yöntemini oluşturduğunuz yere eklemeyi unutmayın: App.Extensions ;
Pawel

UserIdentity.AddClaim satırında hata var. IdentityExtensions sınıfını yalnızca IdentityModels.cs dosyasında oluşturdum. Bu bir sorun kaynağı olabilir mi?
Bu bir tuzak

Hayır, iddiayı eklediğinizde, kimlik uzantıları devreye girmeden çok önce gerçekleşir (bu, değeri geri okuduğunuzda) ... ApplicationUser'ınızın iddia olarak eklemeye çalıştığınız özelliğe sahip olduğundan emin olun: bu örnekte public long OrganizationId {get; Ayarlamak; }
Pawel

6
Teşekkürler, işe yaradı. Asp Net Idendity 2'deki özel değişkenler için en iyi uygulamanın bu olduğunu düşünüyorum. Asp.Net topluluğunun web sitelerindeki varsayılan makalelerde neden böyle bir örnek vermediğini bilmiyorum.
oneNiceFriend

17

Aynı çözümü arıyordum ve Pawel bana cevabın% 99'unu verdi. Uzantının görüntülenmesi için ihtiyacım olan tek şey, aşağıdaki Razor Kodunu cshtml (görünüm) sayfasına eklemekti:

@using programname.Models.Extensions

Kullanıcı oturum açtıktan sonra NavBar'ımın sağ üst köşesinde görüntülenecek FirstName'i arıyordum.

Bu durumda başka birine yardım edeceğimi düşündüm, işte kodum:

Extensions adında yeni bir klasör oluşturdum (Modeller Klasörümün Altında) ve yukarıda belirtildiği gibi yeni sınıfı oluşturdum: 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;
    }
}

Sonra _LoginPartial.cshtml( Views/SharedKlasörlerin Altında ) ekledim@using.ProgramName.Models.Extensions

Ardından, Oturum Açtıktan sonra Kullanıcı Adını kullanacak olan aşağıdaki kod satırına değişikliği ekledim:

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

Belki de bu, çizginin altındaki başka birine yardımcı olur.


11

John Atten tarafından yazılan bu harika blog gönderisine göz atın: ASP.NET Identity 2.0: Kullanıcıları ve Rolleri Özelleştirme

Tüm süreç hakkında adım adım harika bilgilere sahiptir. Git oku :)

İşte bazı temel bilgiler.

Yeni özellikler ekleyerek (yani Adres, Şehir, Eyalet vb.) Varsayılan ApplicationUser sınıfını genişletin:

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

Daha sonra yeni özelliklerinizi RegisterViewModel'inize eklersiniz.

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

Ardından, yeni özellikleri içerecek şekilde Kayıt Görünümünü güncelleyin.

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

Daha sonra AccountController'da Register () yöntemini yeni özelliklerle güncelleyin.

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

16
Bu iyi bir örnek, ancak bu yeni özellikleri User.Identity'den nasıl edinebilirsiniz? Sorusuna cevap vermiyor.
Dejan Bogatinovski

5
Yanıt, özel özelliklerin User.Identity'den nasıl alınabileceğini göstermediği için olumsuz oy verildi.
maulik13

3

ASP.NET Core 2.1'de özel özelliklere nasıl erişileceğini arayan bu soruyu bulan herkes için - çok daha kolay: Bir UserManager'a sahip olacaksınız, örneğin _LoginPartial.cshtml'de ve sonra bunu yapabilirsiniz ("EkranAdı" nın bir IdentityUser'dan devralan kendi AppUser'ınıza eklediğiniz özellik):

@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)Kuruluş Kimliğini almak için veritabanını sorgulayacağına dikkat edilmelidir . Aksine, kabul edilen çözüm iddialarda Organizasyon Kimliği'ni içerecektir (örn. Tanımlama bilgisi). Bu bilgileri veri tabanından çekmenin avantajı, kişilerin çıkış yapmalarına / oturum açmalarına gerek kalmadan kuruluşlar arasında taşınabilmesidir. Elbette dezavantajı, ek bir veritabanı sorgusu gerektirmesidir.
Matt

1

Dhaust, özelliği ApplicationUser sınıfına eklemenin iyi bir yolunu sağlar. OP koduna bakıldığında, bunu yapmış veya yapmak için doğru yolda olmuş olabilirler. Soru sorar

Şu anda oturum açmış olan kullanıcının OrganizationId özelliğini bir denetleyiciden nasıl alabilirim? Ancak OrganizationId, User.Identity'de kullanılabilen bir özellik değildir. User.Identity'yi OrganizationId özelliğini içerecek şekilde genişletmem gerekir mi?

Pawel, ifadelerin kullanılmasını veya ad alanının web.config dosyasına eklenmesini gerektiren bir uzantı yöntemi eklemek için bir yol sunar.

Ancak soru, User.Identity'yi yeni özelliği içerecek şekilde genişletmeniz "gerekip gerekmediğini" sorar. User.Identity'yi genişletmeden mülke erişmenin alternatif bir yolu vardır. Dhaust yöntemini takip ettiyseniz, yeni özelliğe erişmek için denetleyicinizde aşağıdaki kodu kullanabilirsiniz.

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

1

Ayrıca AspNetUsers tabloma ek sütunlar ekledim veya genişlettim. Bu veriyi basitçe incelemek istediğimde, "Uzantılar" vb. İle yukarıdaki kod gibi birçok örnek buldum ... Bu, sadece mevcut kullanıcılardan birkaç değer elde etmek için tüm bu kod satırlarını yazmak zorunda olmanız beni gerçekten şaşırttı.

AspNetUsers tablosunu diğer herhangi bir tablo gibi sorgulayabileceğiniz ortaya çıktı:

 ApplicationDbContext db = new ApplicationDbContext();
 var user = db.Users.Where(x => x.UserName == User.Identity.Name).FirstOrDefault();
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.