ASP.NET MVC 5 - особистість. Як отримати поточний ApplicationUser


237

У моєму проекті є суб'єкт статті, який має ApplicationUserвластивість Author. Як я можу отримати повний об’єкт поточно зареєстрованого ApplicationUser? Створюючи нову статтю, я повинен встановити Authorвластивість у Articleпоточну ApplicationUser.

У старому механізмі членства це було просто, але в новому підході до ідентичності я не знаю, як це зробити.

Я намагався зробити це так:

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

Але я отримую таке виняток:

LINQ для 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вимагає, щоб у вас є наступне використання оператора, щоб доступні не-асинхронні 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. Додайте це в конструктор Controller:

    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
Введіть тип або ім'я UserStore не вдалося. Додано за допомогою Microsft.AspNet.Indentity
Wasfa

2
@Zapnologica: Це звучить як нове запитання (пропонуємо вам його опублікувати). Ви можете розширити ApplicationUserклас (специфічний для програми) та AspNetUsersтаблицю паралельно, і вони нададуть будь-які нові поля. Знову ж таки: Не потрапляйте безпосередньо до бази даних! :)
Пройшов кодування

2
@ LifeH2O: ApplicationUser повертається FindById це ваш клас, в комплекті з вашими додатковими властивостями. Будь ласка, спробуйте.
Пройшов кодування

1
Чекаю вашого нового вирішення: P
Anup Sharma

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. Бачачи, як 15 тис. Людей відвідали питання, я подумав, що це корисна відповідь :)
rtpHarry

2
@TrueBlueAussie, незважаючи на те, що не є прямою відповіддю на питання про ОП, я вважаю, що згадка про використання є дуже корисним доповненням.
StuartQ

1
Для наочності, це тому .GetUserId(), що це метод розширення
FSCKur

11

Код Ellbar працює! Вам потрібно лише додати використання.

1 - using Microsoft.AspNet.Identity;

І ... код Еллбара:

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

За допомогою цього коду (в currentUser) ви працюєте із загальними даними підключеного користувача, якщо вам потрібні додаткові дані ... див. Це посилання


5
Це може "працювати", але, безумовно, не рекомендується обходити доданий API і безпосередньо потрапляти в базу даних. Якщо ви використовували 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
Вже накрили. Перевірте, чи однакова відповідь ще не розміщена (або додайте коментар до існуючої відповіді) :)
Пройшло кодування

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.