ASP.NET MVC 5 - Identität. So erhalten Sie den aktuellen ApplicationUser

237

Ich habe eine Artikelentität in meinem Projekt, deren ApplicationUserEigenschaft benannt ist Author. Wie kann ich das vollständige Objekt der aktuell protokollierten erhalten ApplicationUser? Beim Erstellen eines neuen Artikels muss ich die AuthorEigenschaft Articleauf den aktuellen Wert setzen ApplicationUser.

Im alten Mitgliedschaftsmechanismus war es einfach, aber im neuen Identitätsansatz weiß ich nicht, wie ich das machen soll.

Ich habe es so versucht:

  • Fügen Sie using-Anweisung für Identitätserweiterungen hinzu: using Microsoft.AspNet.Identity;
  • Dann versuche ich den aktuellen Benutzer zu bekommen: ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == User.Identity.GetUserId());

Aber ich bekomme folgende Ausnahme:

LINQ to Entities erkennt die Methode 'System.String GetUserId (System.Security.Principal.IIdentity)' nicht und diese Methode kann nicht in einen Speicherausdruck übersetzt werden. Source = EntityFramework

Ellbar
quelle

Antworten:

448

Sie sollten die Datenbank nicht direkt nach dem aktuellen ApplicationUser abfragen müssen.

Dies führt zu einer neuen Abhängigkeit von einem zusätzlichen Kontext für den Anfang, aber in Zukunft ändern sich die Benutzerdatenbanktabellen (dreimal in den letzten 2 Jahren), aber die API ist konsistent. Beispielsweise wird die usersTabelle jetzt AspNetUsersin Identity Framework aufgerufen , und die Namen mehrerer Primärschlüsselfelder ändern sich ständig, sodass der Code in mehreren Antworten nicht mehr wie er ist funktioniert .

Ein weiteres Problem besteht darin, dass der zugrunde liegende OWIN-Zugriff auf die Datenbank einen separaten Kontext verwendet, sodass Änderungen durch separaten SQL-Zugriff zu ungültigen Ergebnissen führen können (z. B. wenn keine Änderungen an der Datenbank vorgenommen werden). Wieder besteht die Lösung darin, mit der mitgelieferten API zu arbeiten und nicht zu versuchen, sie zu umgehen .

Der korrekte Zugriff auf das aktuelle Benutzerobjekt in der ASP.Net-Identität (zu diesem Datum) ist:

var user = UserManager.FindById(User.Identity.GetUserId());

oder, wenn Sie eine asynchrone Aktion haben, so etwas wie:

var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());

FindByIdVoraussetzung ist, dass Sie die folgende using-Anweisung haben, damit die nicht asynchronen UserManagerMethoden verfügbar sind (es handelt sich um Erweiterungsmethoden für UserManager. Wenn Sie diese nicht einschließen, wird nur angezeigt FindByIdAsync):

using Microsoft.AspNet.Identity;

Wenn Sie sich überhaupt nicht in einem Controller befinden (z. B. wenn Sie die IOC-Injektion verwenden), wird die Benutzer-ID vollständig abgerufen von:

System.Web.HttpContext.Current.User.Identity.GetUserId();

Wenn Sie nicht im Standard-Account-Controller sind, müssen Sie Ihrem Controller Folgendes (als Beispiel) hinzufügen:

1. Fügen Sie diese beiden Eigenschaften hinzu:

    /// <summary>
    /// Application DB context
    /// </summary>
    protected ApplicationDbContext ApplicationDbContext { get; set; }

    /// <summary>
    /// User manager - attached to application DB context
    /// </summary>
    protected UserManager<ApplicationUser> UserManager { get; set; }

2. Fügen Sie dies im Konstruktor des Controllers hinzu:

    this.ApplicationDbContext = new ApplicationDbContext();
    this.UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(this.ApplicationDbContext));

Update März 2015

Hinweis: Mit der letzten Aktualisierung des Identity Frameworks wird eine der zugrunde liegenden Klassen geändert, die für die Authentifizierung verwendet werden. Sie können jetzt über den Owin-Kontext des aktuellen HttpContent darauf zugreifen.

ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(System.Web.HttpContext.Current.User.Identity.GetUserId());

Nachtrag:

Wenn Sie EF und Identity Framework mit Azure über eine entfernte Datenbankverbindung (z. B. Testen des lokalen Hosts zur Azure-Datenbank) verwenden, können Sie zufällig den gefürchteten „Fehler: 19 - Physische Verbindung ist nicht verwendbar“ treffen. Da die Ursache in Identity Framework verborgen ist, wo Sie keine Wiederholungsversuche hinzufügen können (oder was als fehlend erscheint .Include(x->someTable)), müssen Sie eine benutzerdefinierte Funktion SqlAzureExecutionStrategyin Ihrem Projekt implementieren .

Codierung weg
quelle
5
@TBA - danke, ich habe später festgestellt, dass es sich um eine Erweiterungsmethode handelt. Microsoft.AspNet.Identity muss mit hinzugefügt werden.
Sentinel
2
Typ oder Namesapce UserStore konnte nicht gefunden werden. Ich habe mit Microsft.AspNet.Indentity
Wasfa
2
@Zapnologica: Das klingt nach einer neuen Frage (schlagen Sie vor, sie zu posten). Sie können die ApplicationUserKlasse (anwendungsspezifisch) und die AspNetUsersTabelle parallel erweitern und sie stellen alle neuen Felder bereit. Nochmals: Nicht direkt in die Datenbank! :)
Gone Coding
2
@ LifeH2O: Der von FindById zurückgegebene ApplicationUser ist Ihre Klasse mit Ihren zusätzlichen Eigenschaften. Versuch es bitte.
Gone Coding
1
Warten auf Ihre neue Problemumgehung: P
Anup Sharma
60

Mein Fehler, ich hätte keine Methode in einer LINQ-Abfrage verwenden sollen.

Richtiger Code:

using Microsoft.AspNet.Identity;


string currentUserId = User.Identity.GetUserId();
ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);
Ellbar
quelle
2
User.Identiy.GetUserId existiert für mich nicht. ist das ich benutzerdefinierte Methode? Ich komme nur zu User.Identity
Gerrie Pretorius
9
Nevermind ... Sie benötigen das "using Microsoft.AspNet.Identity"; damit diese Methode da ist.
Gerrie Pretorius
4
Nur eine Anmerkung, das Benutzerobjekt ist nur in Controllern sichtbar.
Miro J.
8
Sicherlich sollten Sie UserManagerMethoden verwenden und nicht direkt auf die Datenbank zugreifen?
Gone Coding
3
@ Josh Bjelovuk: Schlagen Sie niemals direkt auf eine Datenbank, wenn eine API verfügbar ist. Dies führt zu einer neuen Abhängigkeit von einem zusätzlichen Kontext für den Anfang, aber in Zukunft ändern sich die Benutzerdatenbanktabellen (dreimal in den letzten 2 Jahren), aber die API ist konsistent.
Gone Coding
33

Es ist in den Kommentaren der Antworten, aber niemand hat dies als die eigentliche Lösung gepostet.

Sie müssen nur oben eine using-Anweisung hinzufügen:

using Microsoft.AspNet.Identity;
rtpHarry
quelle
2
Ich bin mit dieser Ausnahme hierher gekommen, ich habe es damit gelöst using. Als 15.000 Leute die Frage besucht haben, dachte ich, dass es eine hilfreiche Antwort ist :)
rtpHarry
2
@TrueBlueAussie, obwohl dies keine direkte Antwort auf die Frage des OP ist, halte ich die Erwähnung der Verwendung für eine sehr nützliche Ergänzung.
StuartQ
1
Aus Gründen der Klarheit liegt es daran, dass .GetUserId()es sich um eine Erweiterungsmethode handelt
FSCKur
11

Der Code von Ellbar funktioniert! Sie müssen nur mit hinzufügen.

1 - using Microsoft.AspNet.Identity;

Und ... der Code von Ellbar:

2 - string currentUserId = User.Identity.GetUserId(); ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);

Mit diesem Code (in currentUser) bearbeiten Sie die allgemeinen Daten des verbundenen Benutzers, wenn Sie zusätzliche Daten wünschen ... siehe diesen Link

Diego Borges
quelle
5
Es mag "funktionieren", aber es wird sicherlich nicht empfohlen , die bereitgestellte API zu umgehen und direkt auf die Datenbank zuzugreifen. Wenn Sie die API verwendet hätten, würden Sie keine zusätzliche Arbeit benötigen, um die zusätzlichen Daten zu erhalten, wie sie bereits im ApplicationUserObjekt
Gone Coding
Genau! Ich habe jedoch auf diese Weise zurückgegriffen, da ich heute bereits ein System mit einem Lauf in der Datenbank eingerichtet hatte und eine einfache Lösung zur Lösung dieses Problems benötige! Sicherlich würde ich in einem frühen System Objekte in ihre richtigen Klassen und Identitäten einordnen.
Diego Borges
6

Ab ASP.NET Identity 3.0.0 wurde dies überarbeitet

//returns the userid claim value if present, otherwise returns null
User.GetUserId();
Seth IK
quelle
6
ApplicationDbContext context = new ApplicationDbContext();
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
ApplicationUser currentUser = UserManager.FindById(User.Identity.GetUserId());

string ID = currentUser.Id;
string Email = currentUser.Email;
string Username = currentUser.UserName;
Majid Joghataey
quelle
3

Für MVC 5 sehen Sie sich einfach die EnableTwoFactorAuthentication-Methode von ManageController im WebApplication-Vorlagengerüst an.

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> EnableTwoFactorAuthentication()
        {
            await UserManager.SetTwoFactorEnabledAsync(User.Identity.GetUserId(), true);
            var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
            if (user != null)
            {
                await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
            }
            return RedirectToAction("Index", "Manage");
        }

Die Antwort ist genau dort, wie von Microsoft selbst vorgeschlagen:

var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());

Es enthält alle zusätzlichen Eigenschaften, die Sie in der ApplicationUser-Klasse definiert haben.

Paceman
quelle
5
Bereits abgedeckt. Bitte überprüfen Sie, ob eine identische Antwort noch nicht veröffentlicht wurde (oder fügen Sie einen Kommentar zu einer vorhandenen Antwort hinzu) :)
Gone Coding
3

Im Moment erstellt die Projektvorlage asp.mvc einen Account Controller, der den Usermanager auf folgende Weise erhält:

HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>()

Folgendes funktioniert für mich:

ApplicationUser user = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(User.Identity.GetUserId());
Holger Thiemann
quelle
0

Ich war erfolgreich verfügbar, um Anwendungsbenutzer durch Befolgen von Code zu erhalten

var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
            var user = manager.FindById(User.Identity.GetUserId());
            ApplicationUser EmpUser = user;
Abdul Hannan
quelle
0

Falls jemand mit IdentityBenutzern in arbeitet web forms, habe ich es so gemacht:

var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var user = manager.FindById(User.Identity.GetUserId());
Jamshaid Kamran
quelle