133 votes

ASP.NET Core Identity - obtenir l'utilisateur actuel

Pour obtenir l'utilisateur actuellement connecté dans MVC5, il nous suffisait de faire ce qui suit

using Microsoft.AspNet.Identity;
[Authorize]
public IHttpActionResult DoSomething() {
    string currentUserId = User.Identity.GetUserId();
}

Maintenant, avec ASP.NET Core, je pensais que cela devrait fonctionner, mais une erreur se produit.

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Http;

private readonly UserManager<ApplicationUser> _userManager;
[HttpPost]
[Authorize]
public async Task<IActionResult> StartSession() {
    var curUser = await _userManager.GetUserAsync(HttpContext.User);
}

Des idées ?

EDITAR: La réponse de Gerardo est pertinente, mais pour obtenir l'"Id" réel de l'utilisateur, ceci semble fonctionner :

ClaimsPrincipal currentUser = this.User;
var currentUserID = currentUser.FindFirst(ClaimTypes.NameIdentifier).Value;

0 votes

Quelle est votre question exactement ?

0 votes

Vous n'avez besoin que de l'identité ? J'ai modifié ma réponse pour ajouter comment l'obtenir en utilisant la méthode plus sophistiquée _userManager.GetUserId(User).

0 votes

Oui, principalement j'ai besoin de l'Id de la table AspNetUsers, ou de la session. currentUser.FindFirst(ClaimTypes.NameIdentifier).Value donne l'Id en utilisant Claims. Cela fonctionne aussi avec UserManager ! Merci Gerardo ! Est-ce qu'une méthode est plus efficace que l'autre ?

209voto

Gerardo Grignoli Points 782

Si votre code est dans un contrôleur MVC :

public class MyController : Microsoft.AspNetCore.Mvc.Controller

De la Controller vous pouvez obtenir la classe de base ClaimsPrincipal de la User propriété

System.Security.Claims.ClaimsPrincipal currentUser = this.User;

Vous pouvez vérifier les demandes directement (sans aller jusqu'à la base de données) :

bool isAdmin = currentUser.IsInRole("Admin");
var id = _userManager.GetUserId(User); // Get user id:

D'autres champs peuvent être récupérés à partir de l'entité User de la base de données :

  1. Obtenir le gestionnaire d'utilisateurs en utilisant l'injection de dépendances

    private UserManager<ApplicationUser> _userManager;
    
    //class constructor
    public MyController(UserManager<ApplicationUser> userManager)
    {
        _userManager = userManager;
    }
  2. Et utilisez-la :

    var user = await _userManager.GetUserAsync(User);
    var email = user.Email;

Si votre code est une classe de service vous pouvez utiliser l'injection de dépendances pour obtenir une méthode d'évaluation de l'impact sur l'environnement. IHttpContextAccessor qui vous permet d'obtenir le User de l'HttpContext.

    private IHttpContextAccessor _httpContextAccessor;

    public MyClass(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    private void DoSomething()
    {
        var user = _httpContextAccessor.Context?.User;
    }

7 votes

Et si je suis dans une classe de service et non dans le contrôleur, où je n'ai pas la propriété utilisateur ? Comment obtenir l'AppUser-Object de l'utilisateur authentifié ?

20 votes

@Kirsten Vous pouvez recevoir un IHttpContextAccessor avec l'injection de dépendances et ensuite obtenir la User du contexte http. Il suffit d'ajouter ce paramètre au constructeur de la classe de service : IHttpContextAccessor contextAccessor . Garder l'accesseur sur un champ _contextAccessor et ensuite sur les méthodes de service l'obtenir de _contextAccessor.HttpContext.User .

6 votes

@Kirsten Mais en faisant cela, vous couplez votre service avec ASP.NET Core, ce qui le rend inutilisable pour d'autres types de scénarios. Cela peut être acceptable pour vous, ou pas. Je vais également envisager de passer exactement ce que vous voulez au service lors de l'appel de la méthode.

49voto

Greg Gum Points 1441

Si vous utilisez Bearing Token Auth, les exemples ci-dessus ne renvoient pas d'utilisateur d'application.

Au lieu de cela, utilisez ceci :

ClaimsPrincipal currentUser = this.User;
var currentUserName = currentUser.FindFirst(ClaimTypes.NameIdentifier).Value;
ApplicationUser user = await _userManager.FindByNameAsync(currentUserName);

Cela fonctionne dans apsnetcore 2.0. Je n'ai pas essayé dans les versions antérieures.

0 votes

Mes jetons sont validés, mais le principal et les créances ne sont pas définis. Cela se produit dans dotnet core 2.1 et 2.2.

0 votes

@ps2goat, je créerais une nouvelle question pour traiter ce problème, et j'inclurais le code qui crée le jeton.

1 votes

J'ai trouvé la solution. Nous n'avons pas de schéma par défaut car nous avons 5 schémas différents. J'ai dû ajouter un middleware pour décoder le jeton et attribuer les revendications à l'utilisateur actuel. Je devrais probablement rédiger une question et y répondre pour les autres, car il y a très peu de contenu autour de ma situation.

8voto

Joel Palmer Points 21

Pour le contexte, j'ai créé un projet en utilisant le modèle ASP.NET Core 2 Web Application. Ensuite, sélectionnez l'application Web (MVC) puis cliquez sur le bouton Modifier l'authentification et sélectionnez Comptes d'utilisateurs individuels.

Il y a beaucoup d'infrastructures construites pour vous à partir de ce modèle. Trouvez le ManageController dans le dossier Controllers.

Ce site ManageController Le constructeur de la classe requiert que cette variable UserManager soit remplie :

private readonly UserManager<ApplicationUser> _userManager;

Ensuite, jetez un coup d'œil à la méthode [HttpPost] Index de cette classe. Ils obtiennent l'utilisateur actuel de cette façon :

var user = await _userManager.GetUserAsync(User);

En prime, c'est ici que vous voulez mettre à jour tous les champs personnalisés du profil utilisateur que vous avez ajouté à la table AspNetUsers. Ajoutez les champs à la vue, puis soumettez ces valeurs à l'IndexViewModel qui est ensuite soumis à cette méthode Post. J'ai ajouté ce code après la logique par défaut pour définir l'adresse électronique et le numéro de téléphone :

user.FirstName = model.FirstName;
user.LastName = model.LastName;
user.Address1 = model.Address1;
user.Address2 = model.Address2;
user.City = model.City;
user.State = model.State;
user.Zip = model.Zip;
user.Company = model.Company;
user.Country = model.Country;
user.SetDisplayName();
user.SetProfileID();

_dbContext.Attach(user).State = EntityState.Modified;
_dbContext.SaveChanges();

7voto

Bhail Points 425

Dans .NET Core 2.0, l'utilisateur existe déjà en tant que partie du contrôleur hérité sous-jacent. Il suffit d'utiliser l'utilisateur comme vous le feriez normalement ou de le transmettre à tout code de dépôt.

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Policy = "TENANT")]
[HttpGet("issue-type-selection"), Produces("application/json")]
public async Task<IActionResult> IssueTypeSelection()
{
    try
    {
        return new ObjectResult(await _item.IssueTypeSelection(User));
    }
    catch (ExceptionNotFound)
    {
        Response.StatusCode = (int)HttpStatusCode.BadRequest;
        return Json(new
        {
            error = "invalid_grant",
            error_description = "Item Not Found"
        });
    }
}

C'est de là qu'il hérite

#region Assembly Microsoft.AspNetCore.Mvc.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// C:\Users\BhailDa\.nuget\packages\microsoft.aspnetcore.mvc.core\2.0.0\lib\netstandard2.0\Microsoft.AspNetCore.Mvc.Core.dll
#endregion

using System;
using System.IO;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
using Microsoft.AspNetCore.Routing;
using Microsoft.Net.Http.Headers;

namespace Microsoft.AspNetCore.Mvc
{
    //
    // Summary:
    //     A base class for an MVC controller without view support.
    [Controller]
    public abstract class ControllerBase
    {
        protected ControllerBase();

        //
        // Summary:
        //     Gets the System.Security.Claims.ClaimsPrincipal for user associated with the
        //     executing action.
        public ClaimsPrincipal User { get; }

6voto

Dblock247 Points 1256

Si cela intéresse quelqu'un, cela a marché pour moi. J'ai une identité personnalisée qui utilise int pour une clé primaire, donc j'ai remplacé la méthode GetUserAsync.

Surcharge de GetUserAsync

public override Task<User> GetUserAsync(ClaimsPrincipal principal)
{
    var userId = GetUserId(principal);
    return FindByNameAsync(userId);
}

Obtenir l'identité de l'utilisateur

var user = await _userManager.GetUserAsync(User);

Si vous utilisez une clé primaire Guid ordinaire, vous n'avez pas besoin de remplacer GetUserAsync. Tout ceci suppose que votre jeton est configuré correctement.

public async Task<string> GenerateTokenAsync(string email)
{
    var user = await _userManager.FindByEmailAsync(email);
    var tokenHandler = new JwtSecurityTokenHandler();
    var key = Encoding.ASCII.GetBytes(_tokenProviderOptions.SecretKey);

    var userRoles = await _userManager.GetRolesAsync(user);
    var roles = userRoles.Select(o => new Claim(ClaimTypes.Role, o));

    var claims = new[]
    {
        new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
        new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
        new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToString(CultureInfo.CurrentCulture)),
        new Claim(JwtRegisteredClaimNames.GivenName, user.FirstName),
        new Claim(JwtRegisteredClaimNames.FamilyName, user.LastName),
        new Claim(JwtRegisteredClaimNames.Email, user.Email),
    }
    .Union(roles);

    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(claims),
        Expires = DateTime.UtcNow.AddHours(_tokenProviderOptions.Expires),
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
    };

    var token = tokenHandler.CreateToken(tokenDescriptor);

    return Task.FromResult(new JwtSecurityTokenHandler().WriteToken(token)).Result;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X