ASP.NET MVC 5 - личность. Как получить текущий ApplicationUser


237

У меня есть объект Article в моем проекте с ApplicationUserименем свойства Author. Как я могу получить полный объект в настоящее время вошли в систему ApplicationUser? При создании новой статьи я должен установить текущее Authorсвойство .ArticleApplicationUser

В старом механизме членства это было просто, но в новом подходе к идентификации я не знаю, как это сделать.

Я пытался сделать это так:

  • Добавьте оператор using для расширений Identity: using Microsoft.AspNet.Identity;
  • Затем я пытаюсь получить текущий пользователь: ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == User.Identity.GetUserId());

Но я получаю следующее исключение:

LINQ to Entities не распознает метод метода System.String GetUserId (System.Security.Principal.IIdentity), и этот метод нельзя преобразовать в выражение хранилища. Источник = EntityFramework

Ответы:


448

Вам не нужно запрашивать базу данных напрямую для текущего ApplicationUser.

Это вводит новую зависимость наличия дополнительного контекста для начинающих, но в будущем изменения таблиц пользовательских баз данных изменяются (3 раза за последние 2 года), но API является согласованным. Например users, теперь таблица вызывается AspNetUsersв Identity Framework, а имена нескольких полей первичного ключа постоянно меняются, поэтому код в нескольких ответах больше не будет работать как есть .

Другая проблема заключается в том, что основной доступ OWIN к базе данных будет использовать отдельный контекст, поэтому изменения из отдельного доступа SQL могут привести к неверным результатам (например, не видеть изменений, внесенных в базу данных). Опять же, решение состоит в том, чтобы работать с предоставленным API, а не пытаться обойти его.

Правильный способ доступа к текущему объекту пользователя в удостоверении ASP.Net (на данный момент):

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

или, если у вас есть асинхронное действие, что-то вроде:

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

FindByIdтребует наличия следующего оператора using, чтобы не асинхронные UserManagerметоды были доступны (они являются методами расширения для UserManager, поэтому, если вы не включите это, вы увидите только FindByIdAsync):

using Microsoft.AspNet.Identity;

Если вы вообще не находитесь в контроллере (например, используете инъекцию IOC), то идентификатор пользователя полностью извлекается из:

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

Если вы не находитесь в стандартном контроллере учетной записи, вам нужно добавить следующее (в качестве примера) в свой контроллер:

1. Добавьте эти два свойства:

    /// <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. Добавьте это в конструктор контроллера:

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

Обновление март 2015

Примечание . Самое последнее обновление инфраструктуры Identity изменяет один из базовых классов, используемых для аутентификации. Теперь вы можете получить к нему доступ из контекста Owin текущего HttpContent.

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

Приложение:

При использовании EF и Identity Framework с Azure через удаленное соединение с базой данных (например, тестирование локального хоста с базой данных Azure) вы можете случайно нажать на страшную «ошибку: 19 - Физическое соединение не используется». Так как причина скрыта внутри Identity Framework, где вы не можете добавить повторы (или то, что кажется пропущенным .Include(x->someTable)), вам необходимо внедрить пользовательский интерфейс SqlAzureExecutionStrategyв свой проект.


5
@TBA - спасибо, позже я понял, что это метод расширения. Нужно добавить Microsoft.AspNet.Identity используя. еще раз спасибо
Sentinel

2
Тип или namesapce UserStore не может быть найден. Я добавил с помощью Microsft.AspNet.Indentity
Wasfa

2
@Zapnologica: Это звучит как новый вопрос (предлагаю вам опубликовать его). Вы можете расширить ApplicationUserкласс (приложение) и AspNetUsersтаблицу параллельно, и они предоставят любые новые поля. Опять же: не попадайте в базу данных напрямую! :)
Ушел кодирование

2
@ LifeH2O: ApplicationUser, возвращаемый FindById, является вашим классом с вашими дополнительными свойствами. Пожалуйста, попробуйте это.
Ушел кодирование

1
В ожидании вашего нового обходного пути: P
Ануп Шарма

60

Моя ошибка, я не должен был использовать метод внутри запроса LINQ.

Правильный код:

using Microsoft.AspNet.Identity;


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

2
User.Identiy.GetUserId не существует для меня. это я пользовательский метод? Я встаю только до User.Identity
Джерри Преториус

9
Неважно ... вам нужно "использование Microsoft.AspNet.Identity;" чтобы этот метод был там.
Джерри Преториус

4
Просто обратите внимание, объект User виден только в контроллерах.
Миро Дж.

8
Конечно, вы должны использовать UserManagerметоды, а не попадать в базу данных напрямую?
Ушел кодирование

3
@Josh Bjelovuk: Никогда не обращайтесь к базе данных напрямую, когда доступен API. Это вводит новую зависимость наличия дополнительного контекста для начинающих, но в будущем изменения таблиц пользовательских баз данных изменяются (3 раза за последние 2 года), но API является согласованным.
Ушел кодирование

33

Это в комментариях ответов, но никто не опубликовал это как фактическое решение.

Вам просто нужно добавить оператор использования вверху:

using Microsoft.AspNet.Identity;

2
Я пришел сюда с этим исключением, я решил это с этим using. Поскольку 15k человек посетили вопрос, я понял, что это был полезный ответ :)
rtpHarry

2
@TrueBlueAussie, несмотря на то, что я не являюсь прямым ответом на вопрос ОП, я чувствую, что упоминание об использовании является очень полезным дополнением.
StuartQ

1
Для ясности, это потому, что .GetUserId()это метод расширения
FSCKur

11

Код Ellbar работает! Вам нужно только добавить использование.

1 - using Microsoft.AspNet.Identity;

И ... код Ellbar:

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

С этим кодом (in currentUser) вы работаете с общими данными подключенного пользователя, если вам нужны дополнительные данные ... см. Эту ссылку


5
Это может «работать», но, безусловно, не рекомендуется обходить предоставленный API и напрямую обращатьсяApplicationUser
Gone Coding

Я согласен! Тем не менее, прибегли к этому, потому что у меня уже была система на сегодня, с прогоном в базе данных, и мне нужно простое решение для решения этой проблемы! Конечно, в ранней системе я бы помещал объекты в их соответствующие классы и идентичности.
Диего Борхес

6

Начиная с ASP.NET Identity 3.0.0, это было переработано в

//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

Для MVC 5 просто загляните внутрь метода EnableTwoFactorAuthentication ManageController в скаффолде шаблона WebApplication, это делается там:

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

Ответ прямо здесь, как предложено самой Microsoft:

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

Он будет иметь все дополнительные свойства, которые вы определили в классе ApplicationUser.


5
Уже покрыто. Убедитесь, что идентичный ответ еще не опубликован (или добавьте комментарий к существующему ответу) :)
Gone Coding

3

Прямо сейчас шаблон проекта asp.mvc создает контроллер аккаунта, который получает usermanager следующим образом:

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

Следующие работы для меня:

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

0

Я был успешно доступен, чтобы получить пользователя приложения по следующему коду

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

0

В случае, если кто-то работает с Identityпользователями web forms, я получил это, сделав так:

var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var user = manager.FindById(User.Identity.GetUserId());
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.