Używam MVC5 Identity 2.0, aby użytkownicy logowali się do mojej witryny internetowej, gdzie szczegóły uwierzytelniania są przechowywane w bazie danych SQL. Tożsamość Asp.net została zaimplementowana w standardowy sposób, co można znaleźć w wielu samouczkach online.
Klasa ApplicationUser w IdentityModels została rozszerzona o niektóre właściwości niestandardowe, takie jak liczba całkowita OrganizationId. Chodzi o to, że wielu użytkowników można utworzyć i przypisać do wspólnej organizacji na potrzeby relacji z bazą danych.
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; }
}
Jak mogę pobrać właściwość OrganizationId aktualnie zalogowanego użytkownika z poziomu kontrolera? Czy jest to dostępne za pomocą metody, gdy użytkownik jest zalogowany, czy też zawsze pobieram identyfikator organizacji z bazy danych na podstawie identyfikatora użytkownika za każdym razem, gdy jest wykonywana metoda kontrolera?
Czytając w Internecie, zauważyłem, że muszę użyć następujących elementów, aby uzyskać zalogowany identyfikator użytkownika itp.
using Microsoft.AspNet.Identity;
...
User.Identity.GetUserId();
Jednak OrganizationId nie jest właściwością dostępną w User.Identity. Czy muszę rozszerzyć User.Identity, aby uwzględnić właściwość OrganizationId? Jeśli tak, jak mam się do tego zabrać.
Powodem, dla którego potrzebuję identyfikatora OrganizationId tak często, jest to, że wiele zapytań do tabel jest zależnych od identyfikatora OrganizationId w celu pobrania danych odpowiednich dla organizacji, która jest skojarzona z zalogowanym użytkownikiem.
Odpowiedzi:
Ilekroć chcesz rozszerzyć właściwości User.Identity o wszelkie dodatkowe właściwości, takie jak powyższe pytanie, najpierw dodaj te właściwości do klasy ApplicationUser w następujący sposób:
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; } }
Następnie musisz utworzyć taką metodę rozszerzenia (tworzę swoją w nowym folderze Rozszerzenia):
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; } } }
Kiedy tworzysz tożsamość w klasie ApplicationUser, po prostu dodaj Claim -> OrganizationId w następujący sposób:
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; }
Po dodaniu roszczenia i wprowadzeniu metody rozszerzenia, aby udostępnić ją jako właściwość na swoim koncie użytkownika.Tożsamość, dodaj instrukcję using na stronie / pliku, do którego chcesz uzyskać dostęp :
w moim przypadku:
using App.Extensions;
w kontrolerze i za@using. App.Extensions
pomocą pliku widoku .cshtml.EDYTOWAĆ:
Aby uniknąć dodawania instrukcji using w każdym widoku, możesz również przejść do folderu Views i zlokalizować tam plik Web.config. Teraz poszukaj
<namespaces>
tagu i dodaj tam swoją przestrzeń nazw rozszerzenia:<add namespace="App.Extensions" />
Zapisz plik i gotowe. Teraz każdy widok będzie wiedział o twoich rozszerzeniach.
Możesz uzyskać dostęp do metody rozszerzenia:
var orgId = User.Identity.GetOrganizationId();
źródło
Szukałem tego samego rozwiązania i Paweł udzielił mi 99% odpowiedzi. Jedyne, czego mi brakowało, aby rozszerzenie wyświetlało się, to dodanie następującego kodu Razor do strony cshtml (widok):
@using programname.Models.Extensions
Szukałem FirstName, aby wyświetlić w prawym górnym rogu mojego NavBar po zalogowaniu się użytkownika.
Pomyślałem, że opublikuję to, jeśli pomoże to komuś innemu, więc oto mój kod:
Stworzyłem nowy folder o nazwie Extensions (Under my Models Folder) i utworzyłem nową klasę, jak Paweł wskazał powyżej:
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; } }
Następnie w moich
_LoginPartial.cshtml
(PodViews/Shared
folderach) dodałem@using.ProgramName.Models.Extensions
Następnie dodałem zmianę do następującego wiersza kodu, który miał używać imienia użytkownika po zalogowaniu:
@Html.ActionLink("Hello " + User.Identity.GetUserFirstname() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
Być może pomoże to komuś innemu.
źródło
Zapoznaj się z tym świetnym wpisem na blogu autorstwa Johna Attena: ASP.NET Identity 2.0: dostosowywanie użytkowników i ról
Zawiera świetne informacje krok po kroku o całym procesie. Przeczytaj to :)
Oto kilka podstaw.
Rozszerz domyślną klasę ApplicationUser, dodając nowe właściwości (np. Adres, Miasto, Stan itp.):
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); } }
Następnie dodaj nowe właściwości do swojego RegisterViewModel.
// Add the new address properties: public string Address { get; set; } public string City { get; set; } public string State { get; set; }
Następnie zaktualizuj widok rejestru, aby uwzględnić nowe właściwości.
<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>
Następnie zaktualizuj metodę Register () w AccountController przy użyciu nowych właściwości.
// Add the Address properties: user.Address = model.Address; user.City = model.City; user.State = model.State; user.PostalCode = model.PostalCode;
źródło
Dla każdego, kto znajdzie to pytanie, szukając sposobu uzyskania dostępu do właściwości niestandardowych w ASP.NET Core 2.1 - jest to znacznie łatwiejsze: będziesz mieć UserManager, np. W _LoginPartial.cshtml, a następnie możesz po prostu to zrobić (zakładając, że „ScreenName” to właściwość dodana do własnego AppUser, która dziedziczy po 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> }
źródło
GetUserAsync(User)
wysyła zapytanie do bazy danych w celu pobrania OrganizationId. Natomiast przyjęte rozwiązanie będzie zawierało OrganizationId w roszczeniach (np. Plik cookie). Zaletą pobierania tych informacji z bazy danych jest to, że ludzie mogą być przenoszeni między organizacjami bez konieczności wylogowywania się / logowania. Oczywiście wadą jest to, że wymaga dodatkowego zapytania do bazy danych.Wyczerpanie to dobry sposób na dodanie właściwości do klasy ApplicationUser. Patrząc na kod OP, wydaje się, że mogli to zrobić lub byli na dobrej drodze, aby to zrobić. Pytanie zadaje
Paweł daje możliwość dodania metody rozszerzenia, która wymaga użycia instrukcji lub dodania przestrzeni nazw do pliku web.config.
Jednak pojawia się pytanie, czy „trzeba” rozszerzyć User.Identity, aby uwzględnić nową właściwość. Istnieje alternatywny sposób uzyskiwania dostępu do właściwości bez rozszerzania właściwości User.Identity. Jeśli zastosowałeś metodę Wyczerpywanie, możesz użyć następującego kodu w kontrolerze, aby uzyskać dostęp do nowej właściwości.
ApplicationDbContext db = new ApplicationDbContext(); var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db)); var currentUser = manager.FindById(User.Identity.GetUserId()); var myNewProperty = currentUser.OrganizationId;
źródło
Dodałem również lub rozszerzyłem dodatkowe kolumny do mojej tabeli AspNetUsers. Kiedy chciałem po prostu przejrzeć te dane, znalazłem wiele przykładów, takich jak powyższy kod z "Rozszerzeniami" itp. To naprawdę zdziwiło mnie, że trzeba było napisać wszystkie te linie kodu, aby uzyskać kilka wartości od obecnych użytkowników.
Okazuje się, że możesz wysyłać zapytania do tabeli AspNetUsers jak w przypadku każdej innej tabeli:
ApplicationDbContext db = new ApplicationDbContext(); var user = db.Users.Where(x => x.UserName == User.Identity.Name).FirstOrDefault();
źródło