ASP.NET MVC 5 - Identité. Comment obtenir l'actuel ApplicationUser

237

J'ai une entité Article dans mon projet qui a la ApplicationUserpropriété nommée Author. Comment puis-je obtenir l'objet complet de actuellement connecté ApplicationUser? Lors de la création d'un nouvel article, je dois définir la Authorpropriété Articlesur l'actuelle ApplicationUser.

Dans l'ancien mécanisme d'adhésion, c'était simple, mais dans la nouvelle approche d'identité, je ne sais pas comment faire.

J'ai essayé de le faire de cette façon:

  • Ajouter une instruction using pour les extensions d'identité: using Microsoft.AspNet.Identity;
  • Ensuite, j'essaie d'obtenir l'utilisateur actuel: ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == User.Identity.GetUserId());

Mais je reçois l'exception suivante:

LINQ to Entities ne reconnaît pas la méthode «System.String GetUserId (System.Security.Principal.IIdentity)» et cette méthode ne peut pas être traduite en une expression de magasin. Source = EntityFramework

Ellbar
la source

Réponses:

448

Vous ne devez pas avoir à interroger la base de données directement pour l'ApplicationUser en cours.

Cela introduit une nouvelle dépendance d'avoir un contexte supplémentaire pour les démarreurs, mais à l'avenir, les tables de base de données utilisateur changent (3 fois au cours des 2 dernières années) mais l'API est cohérente. Par exemple, la userstable est désormais appelée AspNetUsersdans Identity Framework et les noms de plusieurs champs de clé primaire ne cessent de changer, de sorte que le code dans plusieurs réponses ne fonctionnera plus tel quel .

Un autre problème est que l'accès OWIN sous-jacent à la base de données utilisera un contexte distinct, de sorte que les modifications d'un accès SQL séparé peuvent produire des résultats invalides (par exemple, ne pas voir les modifications apportées à la base de données). Encore une fois, la solution est de travailler avec l'API fournie et de ne pas essayer de la contourner .

La façon correcte d'accéder à l'objet utilisateur actuel dans l'identité ASP.Net (à cette date) est:

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

ou, si vous avez une action asynchrone, quelque chose comme:

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

FindByIdnécessite que vous disposiez de l' instruction using suivante pour que les UserManagerméthodes non asynchrones soient disponibles (ce sont des méthodes d'extension pour UserManager, donc si vous ne les incluez pas, vous ne verrez que FindByIdAsync):

using Microsoft.AspNet.Identity;

Si vous n'êtes pas du tout dans un contrôleur (par exemple, vous utilisez l'injection IOC), l'ID utilisateur est récupéré en entier à partir de:

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

Si vous n'êtes pas dans le contrôleur de compte standard, vous devrez ajouter les éléments suivants (à titre d'exemple) à votre contrôleur:

1. Ajoutez ces deux propriétés:

    /// <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. Ajoutez ceci dans le constructeur du contrôleur:

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

Mise à jour mars 2015

Remarque: La mise à jour la plus récente du framework Identity modifie l'une des classes sous-jacentes utilisées pour l'authentification. Vous pouvez maintenant y accéder à partir du contexte Owin du contenu HttpContent actuel.

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

Addenda:

Lorsque vous utilisez EF et Identity Framework avec Azure, sur une connexion à une base de données distante (par exemple, un test d'hôte local vers une base de données Azure), vous pouvez frapper au hasard la redoutable «erreur: 19 - La connexion physique n'est pas utilisable». Comme la cause est enfouie dans Identity Framework, où vous ne pouvez pas ajouter de nouvelles tentatives (ou ce qui semble être manquant .Include(x->someTable)), vous devez implémenter une personnalisation SqlAzureExecutionStrategydans votre projet.

Fin du codage
la source
5
@TBA - merci, j'ai réalisé plus tard que c'est une méthode d'extension. Besoin d'ajouter Microsoft.AspNet.Identity à l'aide de. merci encore
Sentinel
2
Type ou espace de noms UserStore introuvable. J'ai ajouté à l'aide de Microsft.AspNet.Indentity
Wasfa
2
@Zapnologica: Cela ressemble à une nouvelle question (je vous suggère de la poster). Vous pouvez étendre la ApplicationUserclasse (spécifique à l'application) et la AspNetUserstable en parallèle et ils fourniront de nouveaux champs. Encore une fois: ne frappez pas directement la base de données! :)
Gone Coding
2
@ LifeH2O: l'ApplicationUser renvoyé par FindById est votre classe, avec vos propriétés supplémentaires. Essayez-le.
codage
1
En attente de votre nouvelle solution: P
Anup Sharma
60

Mon erreur, je n'aurais pas dû utiliser une méthode dans une requête LINQ.

Code correct:

using Microsoft.AspNet.Identity;


string currentUserId = User.Identity.GetUserId();
ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);
Ellbar
la source
2
User.Identiy.GetUserId n'existe pas pour moi. est-ce que je méthode personnalisée? Je me lève seulement sur User.Identity
Gerrie Pretorius
9
Peu importe ... vous avez besoin du "using Microsoft.AspNet.Identity;" pour que cette méthode soit là.
Gerrie Pretorius
4
Juste une note, l'objet utilisateur n'est visible que dans les contrôleurs.
Miro J.31
8
Vous devriez sûrement utiliser des UserManagerméthodes et ne pas toucher directement la base de données?
Fin du codage du
3
@Josh Bjelovuk: Ne frappez jamais une base de données directement lorsqu'une API est disponible. Cela introduit une nouvelle dépendance d'avoir un contexte supplémentaire pour les démarreurs, mais à l'avenir, les tables de base de données utilisateur changent (3 fois au cours des 2 dernières années) mais l'API est cohérente.
Fin du codage
33

C'est dans les commentaires des réponses mais personne n'a posté cela comme la vraie solution.

Vous avez juste besoin d'ajouter une instruction using en haut:

using Microsoft.AspNet.Identity;
rtpHarry
la source
2
Je suis venu ici avec cette exception, je l'ai résolu avec ça using. Étant donné que 15 000 personnes ont visité la question, j'ai pensé que c'était une réponse utile :)
rtpHarry
2
@TrueBlueAussie, bien qu'il ne s'agisse pas d'une réponse directe à la question OP, je pense que mentionner l'utilisation est un ajout très utile.
StuartQ
1
Pour plus de clarté, c'est parce que .GetUserId()c'est une méthode d'extension
FSCKur
11

Le code d'Ellbar fonctionne! Vous avez seulement besoin d'ajouter en utilisant.

1 - using Microsoft.AspNet.Identity;

Et ... le code d'Ellbar:

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

Avec ce code (in currentUser), vous travaillez les données générales de l'utilisateur connecté, si vous voulez des données supplémentaires ... voir ce lien

Diego Borges
la source
5
Cela peut "fonctionner", mais il n'est certainement pas recommandé de contourner l'API fournie et d'accéder directement à la base de données.Si vous avez utilisé l'API, vous n'auriez pas besoin de travail supplémentaire pour obtenir les données supplémentaires telles qu'elles seraient déjà dans l' ApplicationUserobjet
Gone Coding
Je suis d'accord! Cependant, j'ai recouru à cette méthode car j'avais déjà un système en place aujourd'hui, avec un run dans la base de données et j'ai besoin d'une solution simple pour résoudre ce problème! Certes, dans un système ancien, je mettrais les objets dans leurs propres classes et identités.
Diego Borges
6

Depuis ASP.NET Identity 3.0.0, cela a été refactorisé en

//returns the userid claim value if present, otherwise returns null
User.GetUserId();
Seth IK
la source
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
la source
3

Pour MVC 5, regardez simplement à l'intérieur de la méthode EnableTwoFactorAuthentication de ManageController dans l'échafaudage de modèle WebApplication, cela se fait 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 réponse est là, comme l'a suggéré Microsoft lui-même:

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

Il aura toutes les propriétés supplémentaires que vous avez définies dans la classe ApplicationUser.

Paceman
la source
5
Déjà couvert. Veuillez vérifier qu'une réponse identique n'est pas déjà publiée (ou ajouter un commentaire à une réponse existante) :)
Fin du codage
3

À l'heure actuelle, le modèle de projet asp.mvc crée un contrôleur de compte qui obtient le gestionnaire d'utilisateurs de cette façon:

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

Ce qui suit fonctionne pour moi:

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

J'étais disponible pour obtenir l'utilisateur de l'application en suivant le morceau de code

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

Si quelqu'un travaille avec des Identityutilisateurs web forms, je l'ai fait fonctionner en le faisant:

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