ASP.NET MVC 5 - Identità. Come ottenere ApplicationUser corrente


237

Ho un'entità articolo nel mio progetto che ha la ApplicationUserproprietà denominata Author. Come posso ottenere l'intero oggetto attualmente registrato ApplicationUser? Durante la creazione di un nuovo articolo, devo impostare la Authorproprietà Articlesulla corrente ApplicationUser.

Nel vecchio meccanismo di appartenenza era semplice, ma nel nuovo approccio Identity non so come farlo.

Ho provato a farlo in questo modo:

  • Aggiungi dichiarazione usando per le estensioni di identità: using Microsoft.AspNet.Identity;
  • Quindi provo a ottenere l'utente corrente: ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == User.Identity.GetUserId());

Ma ottengo la seguente eccezione:

LINQ to Entities non riconosce il metodo "System.String GetUserId (System.Security.Principal.IIdentity)" e questo metodo non può essere tradotto in un'espressione di archivio. Fonte = EntityFramework

Risposte:


448

Non è necessario interrogare direttamente il database per l'attuale ApplicationUser.

Ciò introduce una nuova dipendenza dall'avere un contesto aggiuntivo per i principianti, ma andando avanti le tabelle del database degli utenti cambiano (3 volte negli ultimi 2 anni) ma l'API è coerente. Ad esempio, la userstabella viene ora chiamata AspNetUsersin Identity Framework e i nomi di diversi campi chiave primaria continuano a cambiare, quindi il codice in diverse risposte non funzionerà più così com'è .

Un altro problema è che l'accesso OWIN sottostante al database utilizzerà un contesto separato, quindi le modifiche dall'accesso SQL separato possono produrre risultati non validi (ad esempio non vedere le modifiche apportate al database). Ancora una volta la soluzione è lavorare con l'API fornita e non tentare di aggirarla .

Il modo corretto di accedere all'oggetto utente corrente nell'identità ASP.Net (a questa data) è:

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

o, se hai un'azione asincrona, qualcosa del tipo:

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

FindByIdrichiede di disporre della seguente istruzione using in modo che i UserManagermetodi non asincroni siano disponibili (sono metodi di estensione per UserManager, quindi se non si include questo si vedrà solo FindByIdAsync):

using Microsoft.AspNet.Identity;

Se non si utilizza affatto un controller (ad es. Si utilizza l'iniezione IOC), l'ID utente viene recuperato per intero da:

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

Se non ti trovi nel controller dell'account standard, dovrai aggiungere quanto segue (come esempio) al controller:

1. Aggiungi queste due proprietà:

    /// <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. Aggiungi questo nel costruttore del controller:

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

Aggiornamento marzo 2015

Nota: l'aggiornamento più recente al framework Identity modifica una delle classi sottostanti utilizzate per l'autenticazione. Ora puoi accedervi dal contesto Owin dell'attuale HttpContent.

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

Addendum:

Quando si utilizza EF e Identity Framework con Azure, tramite una connessione al database remoto (ad esempio test dell'host locale nel database di Azure), è possibile colpire in modo casuale il temuto "errore: 19 - La connessione fisica non è utilizzabile". Poiché la causa viene seppellita all'interno di Identity Framework, dove non è possibile aggiungere nuovi tentativi (o ciò che sembra mancare .Include(x->someTable)), è necessario implementare un'abitudine SqlAzureExecutionStrategynel progetto.


5
@TBA - grazie, mi sono reso conto in seguito che è un metodo di estensione. È necessario aggiungere Microsoft.AspNet.Identity utilizzando. grazie ancora
Sentinel,

2
Impossibile trovare UserStore di tipo o namespace. Ho aggiunto utilizzando Microsft.AspNet.Indentity
Wasfa il

2
@Zapnologica: sembra una nuova domanda (suggerisci di pubblicarla). È possibile estendere la ApplicationUserclasse (specifica dell'applicazione) e la AspNetUserstabella in parallelo e forniranno tutti i nuovi campi. Ancora: non colpire direttamente il database! :)
Codice andato finito il

2
@ LifeH2O: ApplicationUser restituito da FindById è la tua classe, completa delle tue proprietà extra. Per favore, provalo
Codice finito

1
Aspettando la tua nuova soluzione alternativa: P
Anup Sharma,

60

Errore mio, non avrei dovuto usare un metodo all'interno di una query LINQ.

Codice corretto:

using Microsoft.AspNet.Identity;


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

2
User.Identiy.GetUserId non esiste per me. è quel metodo personalizzato? Mi rivolgo solo a User.Identity
Gerrie Pretorius

9
Non importa ... hai bisogno del "using Microsoft.AspNet.Identity;" per quel metodo essere lì.
Gerrie Pretorius,

4
Solo una nota, l'oggetto Utente è visibile solo in Controller.
Miro J.,

8
Sicuramente dovresti usare UserManagermetodi e non colpire direttamente il database?
Codice finito

3
@Josh Bjelovuk: non colpire mai direttamente un database quando è disponibile un'API. Ciò introduce una nuova dipendenza dall'avere un contesto aggiuntivo per i principianti, ma andando avanti le tabelle del database degli utenti cambiano (3 volte negli ultimi 2 anni) ma l'API è coerente.
Codice finito

33

È nei commenti delle risposte, ma nessuno ha pubblicato questo come la soluzione effettiva.

Devi solo aggiungere un'istruzione using in alto:

using Microsoft.AspNet.Identity;

2
Sono venuto qui con quell'eccezione, l'ho risolto con quello using. Visto che 15.000 persone hanno visitato la domanda, ho pensato che fosse una risposta utile :)
rtpHarry,

2
@TrueBlueAussie, nonostante non sia una risposta diretta alla domanda dei PO, ritengo che menzionare l'utilizzo sia un'aggiunta molto utile.
StuartQ,

1
Per chiarezza, è perché .GetUserId()è un metodo di estensione
FSCKur

11

Il codice di Ellbar funziona! Devi solo aggiungere usando.

1 - using Microsoft.AspNet.Identity;

E ... il codice di Ellbar:

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

Con questo codice (in currentUser), si lavorano i dati generali dell'utente connesso, se si desidera ulteriori dati ... vedere questo collegamento


5
Potrebbe "funzionare", ma di certo non è consigliabile ignorare l'API fornita e colpire direttamente il database. Se hai utilizzato l'API non avresti bisogno di ulteriore lavoro per ottenere i dati extra come sarebbero già ApplicationUsernell'oggetto
Codice andato

Sono d'accordo! Tuttavia, ho fatto ricorso in questo modo perché avevo già installato un sistema oggi, con una corsa nel database e ho bisogno di una soluzione semplice per risolvere questo problema! Certamente, in un sistema iniziale, inserivo gli oggetti nelle loro classi e identità.
Diego Borges,

6

A partire da ASP.NET Identity 3.0.0, questo è stato modificato in

//returns the userid claim value if present, otherwise returns null
User.GetUserId();

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;

3

Per MVC 5 basta guardare all'interno del metodo EnableTwoFactorAuthentication di ManageController nello scaffold del modello WebApplication, che viene fatto lì:

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

La risposta è proprio lì come suggerito dalla stessa Microsoft:

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

Avrà tutte le proprietà aggiuntive definite nella classe ApplicationUser.


5
Già coperto. Verifica che non sia già stata pubblicata una risposta identica (o aggiungi un commento a una risposta esistente) :)
Codice andato

3

In questo momento il modello di progetto asp.mvc crea un controller di account che ottiene l'utente in questo modo:

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

Per me funziona quanto segue:

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

0

Ero disponibile con successo per ottenere l'utente dell'applicazione seguendo il pezzo di codice

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

0

Nel caso in cui qualcuno stia lavorando con gli Identityutenti web forms, ho capito come funziona:

var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var user = manager.FindById(User.Identity.GetUserId());
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.