ASP.NET Core Identity - отримати поточного користувача


83

Щоб отримати поточно зареєстрованого користувача в MVC5, нам потрібно було лише:

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

Тепер, з ASP.NET Core, я вважав, що це має працювати, але це видає помилку.

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

Будь-які ідеї?

РЕДАКТУВАТИ: відповідь Герардо йде, але, щоб отримати фактичний "ідентифікатор" користувача, це, здається, працює:

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

Яке саме ваше запитання?
Gerardo Grignoli

Вам потрібен лише ідентифікатор? Я відредагував свою відповідь, щоб додати, як її отримати за допомогою більш вигадливого _userManager.GetUserId (Користувач)
Gerardo Grignoli

Так, в першу чергу мені потрібен ідентифікатор із таблиці AspNetUsers або з сеансу. currentUser.FindFirst (ClaimTypes.NameIdentifier) ​​.Value дає ідентифікатор, використовуючи Claims. Це також працює з UserManager! Дякую Херардо! Чи є один спосіб ефективнішим за інший?
jbraun

UserManager внутрішньо робить .FindFirst (ClaimTypes.NameIdentifier). Тож це однаково щодо продуктивності. Я віддаю перевагу інкапсуляції usermanager для зручності читання. З іншого боку, .GetUserAsync()це повільніше, оскільки воно надходить до БД.
Gerardo Grignoli

Я повністю погоджуюсь з Херардо. Дякую !
jbraun

Відповіді:


144

Припускаючи, що ваш код знаходиться всередині контролера MVC:

public class MyController : Microsoft.AspNetCore.Mvc.Controller

З Controllerбазового класу ви можете отримати IClaimsPrincipalз Userвласності

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

Ви можете перевірити претензії безпосередньо (без зворотного шляху до бази даних):

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

Інші поля можна отримати з сутності користувача бази даних:

  1. Отримайте менеджер користувачів за допомогою ін’єкції залежностей

    private UserManager<ApplicationUser> _userManager;
    
    //class constructor
    public MyController(UserManager<ApplicationUser> userManager)
    {
        _userManager = userManager;
    }
    
  2. І використовуйте його:

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

6
І якщо я перебуваю в класі обслуговування, а не в контролері, де я не маю Властивості користувача? Як отримати AppUser-Object автентифікованого користувача?
Кірстен

13
@Kirsten Ви можете отримати IHttpContextAccessorін'єкцію залежностей, а потім отримати Userз контексту http. Просто додайте параметри в конструктор класу обслуговування: IHttpContextAccessor contextAccessor. Тримайте аксесуар у полі, _contextAccessorа потім на методах обслуговування, щоб отримати його _contextAccessor.HttpContext.User.
Gerardo Grignoli

5
@Kirsten Але це робить вашу службу поєднаною з ASP.NET Core, роблячи її непридатною для використання в інших сценаріях. Це може бути прийнятним для вас чи ні. Я також розгляну передачу саме того, що ви хочете, службі під час виклику методу.
Gerardo Grignoli

2
Ви підштовхнули мене правильно: я створив IUserService за допомогою GetUser та IsAuthenticated. У моїй програмі ASP.NET Core у мене є реалізація userService, яка використовує IHttpContextAccessor та UserManager <ApplicationUser>. Отже, моя userService пов’язана з ASP.NET Core, інші мої служби - ні.
Кірстен

2
Ні, вони не переходять до бази даних. Перевіряючи джерело, вони не використовують UserStore. github.com/dotnet/corefx/blob/master/src/System.Security.Claims/… github.com/aspnet/Identity/blob/…
Герардо Гриньолі,

34

Якщо ви використовуєте Bearing Token Auth, наведені вище зразки не повертають користувача програми.

Натомість використовуйте це:

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

Це працює в apsnetcore 2.0. Не пробував у попередніх версіях.


Мої жетони перевіряються, але основна та претензії не встановлюються. Це відбувається в dotnet core 2.1 та 2.2
ps2goat

@ ps2goat, я створив би нове запитання для вирішення цього питання та включив би код, що створює маркер.
Greg Gum

1
Я зрозумів це. У нас немає схеми за замовчуванням, оскільки у нас є 5 різних схем. Мені довелося додати проміжне програмне забезпечення, щоб декодувати маркер і призначити претензії поточному користувачеві. Ймовірно, мені слід написати питання та відповісти на нього іншим, оскільки в моїй ситуації дуже мало вмісту.
ps2goat

1
ClaimTypes.Name отримує ім'я користувача, яке те, що я шукав, замість Id. ClaimTypes.NameIdentifier отримує ідентифікатор користувача. Про всяк випадок, якщо хтось це побачить і задається питанням, як отримати ім’я користувача. Дякую за вашу відповідь Грег!
Метью Зуреліас,

7

Для контексту я створив проект, використовуючи шаблон веб-програми ASP.NET Core 2. Потім виберіть веб-програму (MVC), натисніть кнопку Змінити автентифікацію та виберіть Індивідуальні облікові записи користувачів.

За цим шаблоном для вас створено багато інфраструктури. Знайдіть ManageControllerу папці Контролери.

Цей ManageControllerконструктор класів вимагає заповнення цієї змінної UserManager:

private readonly UserManager<ApplicationUser> _userManager;

Потім погляньте на метод індексу [HttpPost] у цьому класі. Вони отримують поточного користувача таким чином:

var user = await _userManager.GetUserAsync(User);

Як додаткове зауваження, саме тут ви хочете оновити будь-які власні поля до профілю користувача, який ви додали до таблиці AspNetUsers. Додайте поля до подання, а потім надішліть ці значення до IndexViewModel, який потім подається до цього методу публікації. Я додав цей код після логіки за замовчуванням, щоб встановити адресу електронної пошти та номер телефону:

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

5

У .NET Core 2.0 користувач уже існує як частина базового успадкованого контролера. Просто використовуйте Користувача, як зазвичай, або переходьте до будь-якого коду сховища.

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

Звідси він успадковує це

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

2

Просто якщо хтось зацікавлений, це спрацювало для мене. У мене є власна ідентичність, яка використовує int для первинного ключа, тому я замінив метод GetUserAsync

Замінити GetUserAsync

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

Отримати ідентифікаційного користувача

var user = await _userManager.GetUserAsync(User);

Якщо ви використовуєте звичайний первинний ключ Guid, вам не потрібно перевизначати GetUserAsync. Це все припускає, що ваш маркер налаштовано правильно.

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

1
private readonly UserManager<AppUser> _userManager;

 public AccountsController(UserManager<AppUser> userManager)
 {
            _userManager = userManager;
 }

[Authorize(Policy = "ApiUser")]
[HttpGet("api/accounts/GetProfile", Name = "GetProfile")]
public async Task<IActionResult> GetProfile()
{
   var userId = ((ClaimsIdentity)User.Identity).FindFirst("Id").Value;
   var user = await _userManager.FindByIdAsync(userId);

   ProfileUpdateModel model = new ProfileUpdateModel();
   model.Email = user.Email;
   model.FirstName = user.FirstName;
   model.LastName = user.LastName;
   model.PhoneNumber = user.PhoneNumber;

   return new OkObjectResult(model);
}

0

Я помістив щось подібне до свого класу Controller, і це спрацювало:

IdentityUser user = await userManager.FindByNameAsync(HttpContext.User.Identity.Name);

де userManager - це екземпляр класу Microsoft.AspNetCore.Identity.UserManager (з усіма дивовижними налаштуваннями).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.