it-swarm.com.de

So erweitern Sie die verfügbaren Eigenschaften von User.Identity

Ich verwende MVC5 Identity 2.0, damit Benutzer sich auf meiner Website anmelden können. Dort werden die Authentifizierungsdetails in einer SQL-Datenbank gespeichert. Asp.net Identity wurde wie in vielen Online-Tutorials üblich implementiert.

Die ApplicationUser-Klasse in IdentityModels wurde um einige benutzerdefinierte Eigenschaften erweitert, z. B. eine ganzzahlige OrganizationId. Die Idee ist, dass viele Benutzer zu Zwecken der Datenbankbeziehung erstellt und einer gemeinsamen Organisation zugewiesen werden können.

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

Wie kann ich die OrganizationId-Eigenschaft des aktuell angemeldeten Benutzers von einem Controller aus abrufen? Steht dies über eine Methode zur Verfügung, sobald ein Benutzer angemeldet ist, oder muss ich bei jeder Ausführung einer Controllermethode immer die Organisations-ID anhand der Benutzer-ID aus der Datenbank abrufen?

Ich habe im Internet herumgelesen und gesehen, dass ich Folgendes verwenden muss, um die eingeloggte Benutzer-ID usw. zu erhalten.

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

OrganizationId ist jedoch keine in User.Identity verfügbare Eigenschaft. Muss ich User.Identity erweitern, um die OrganizationId-Eigenschaft einzuschließen? Wenn ja, wie gehe ich vor?.

Der Grund, warum ich die Organisations-ID so oft benötige, ist, dass viele Tabellenabfragen auf die Organisations-ID angewiesen sind, um Daten abzurufen, die für die Organisation relevant sind und die dem angemeldeten Benutzer zugeordnet sind.

120
RobHurd

Wenn Sie die Eigenschaften von User.Identity mit zusätzlichen Eigenschaften wie der obigen Frage erweitern möchten, fügen Sie der ApplicationUser-Klasse zunächst die folgenden Eigenschaften hinzu:

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

Dann müssen Sie eine Erweiterungsmethode wie diese erstellen (ich erstelle meine in einem neuen Extensions-Ordner):

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

Wenn Sie die Identität in der ApplicationUser-Klasse erstellen, fügen Sie einfach die Claim -> OrganizationId wie folgt hinzu:

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

Nachdem Sie den Anspruch hinzugefügt und Ihre Erweiterungsmethode eingerichtet haben, können Sie ihn als Eigenschaft für Ihre User.Identity verfügbar machen. Fügen Sie eine using-Anweisung zu der Seite/Datei hinzu, auf die Sie zugreifen möchten.

in meinem Fall: using App.Extensions; innerhalb eines Controllers und @using. App.Extensions mit einer .cshtml View Datei.

BEARBEITEN:

Sie können auch verhindern, dass in jeder Ansicht eine using-Anweisung hinzugefügt wird, indem Sie in den Ordner "Views" wechseln und dort die Datei "Web.config" suchen. Nun suchen Sie nach dem <namespaces> tagge und füge dort deinen Extension Namespace so hinzu:

<add namespace="App.Extensions" />

Speichern Sie Ihre Datei und Sie sind fertig. Jetzt kennt jede Ansicht Ihre Erweiterungen.

Sie können auf die Erweiterungsmethode zugreifen:

var orgId = User.Identity.GetOrganizationId();

Hoffe das hilft jedem :)

206
Pawel

Ich suchte nach der gleichen Lösung und Pawel gab mir 99% der Antwort. Das einzige, was fehlte, um die Erweiterung anzuzeigen, war das Hinzufügen des folgenden Razor-Codes zur Seite cshtml (view):

@using programname.Models.Extensions

Ich habe nach dem Vornamen gesucht, der rechts oben in meiner Navigationsleiste angezeigt werden soll, nachdem sich der Benutzer angemeldet hat.

Ich dachte, ich würde dies posten, falls es jemand anderem hilft. Also hier ist mein Code:

Ich habe einen neuen Ordner namens Extensions (Under my Models Folder) erstellt und die neue Klasse als Pawel wie oben angegeben erstellt: 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;
    }
}

Dann habe ich in meinen _LoginPartial.cshtml (Unter Views/Shared Ordnern) @using.ProgramName.Models.Extensions Hinzugefügt.

Anschließend habe ich die Änderung in die folgende Codezeile eingefügt, in der nach der Anmeldung der Vorname des Benutzers verwendet werden sollte:

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

Vielleicht hilft das jemand anderem auf der ganzen Linie.

16
AxleWack

Sehen Sie sich diesen großartigen Blog-Beitrag von John Atten an: ASP.NET Identity 2.0: Anpassen von Benutzern und Rollen

Es gibt tolle Schritt-für-Schritt-Informationen über den gesamten Prozess. Geh es lesen:)

Hier sind einige der Grundlagen.

Erweitern Sie die standardmäßige ApplicationUser-Klasse, indem Sie neue Eigenschaften hinzufügen (z. B. Adresse, Stadt, Bundesland usw.):

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

Dann fügen Sie Ihrem RegisterViewModel Ihre neuen Eigenschaften hinzu.

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

Aktualisieren Sie dann die Registeransicht, um die neuen Eigenschaften einzuschließen.

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

Aktualisieren Sie anschließend die Register () - Methode in AccountController mit den neuen Eigenschaften.

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

Für alle, die diese Frage nach dem Zugriff auf benutzerdefinierte Eigenschaften in ASP.NET Core 2.1 suchen, ist dies viel einfacher: Sie verfügen über einen UserManager, z. in _LoginPartial.cshtml, und dann können Sie einfach tun (vorausgesetzt, "ScreenName" ist eine Eigenschaft, die Sie zu Ihrem eigenen AppUser hinzugefügt haben, der von IdentityUser erbt):

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

Mit Dhaust können Sie die Eigenschaft der ApplicationUser-Klasse hinzufügen. Wenn man sich den OP-Code ansieht, scheint es, dass sie dies getan haben oder auf dem richtigen Weg waren, dies zu tun. Die Frage stellt sich

Wie kann ich die OrganizationId-Eigenschaft des aktuell angemeldeten Benutzers von einem Controller aus abrufen? OrganizationId ist jedoch keine in User.Identity verfügbare Eigenschaft. Muss ich User.Identity erweitern, um die OrganizationId-Eigenschaft einzuschließen?

Pawel bietet die Möglichkeit, eine Erweiterungsmethode hinzuzufügen, die die Verwendung von Anweisungen oder das Hinzufügen des Namespace zur Datei web.config erfordert.

In der Frage wird jedoch gefragt, ob Sie User.Identity erweitern müssen, um die neue Eigenschaft einzuschließen. Es gibt eine alternative Möglichkeit, auf die Eigenschaft zuzugreifen, ohne User.Identity zu erweitern. Wenn Sie der Dhaust-Methode gefolgt sind, können Sie den folgenden Code in Ihrem Controller verwenden, um auf die neue Eigenschaft zuzugreifen.

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
codeMethod

Ich hatte auch zusätzliche Spalten in meiner AspNetUsers-Tabelle hinzugefügt oder erweitert. Als ich diese Daten einfach ansehen wollte, fand ich viele Beispiele wie den obigen Code mit "Extensions" usw. Das hat mich wirklich erstaunt, dass Sie all diese Codezeilen schreiben mussten, um ein paar Werte von den aktuellen Benutzern zu erhalten.

Es stellt sich heraus, dass Sie die AspNetUsers-Tabelle wie jede andere Tabelle abfragen können:

 ApplicationDbContext db = new ApplicationDbContext();
 var user = db.Users.Where(x => x.UserName == User.Identity.Name).FirstOrDefault();
0
Anthony Griggs