Треба сказати, що я був дуже здивований, що HttpContext є нульовим усередині конструктора. Я впевнений, що це з міркувань продуктивності. Підтвердили, що, IPrincipal
як описано нижче, вводять його в конструктор. По суті, це робиться так само, як прийнята відповідь, але більш інтерфейсно.
Кожен, хто знайде це питання, шукає відповідь на загальне "Як отримати поточного користувача?" Ви можете просто отримати доступ User
безпосередньо з Controller.User
. Але ви можете це робити лише у внутрішніх методах дій (я припускаю, що контролери не працюють лише з HttpContexts і з міркувань продуктивності).
Однак - якщо вам це потрібно в конструкторі (як це робилося в ОП) або потрібно створити інші об'єкти, які можна вводити, які потребують поточного користувача, то нижче - кращий підхід:
Введіть IPrincipal, щоб отримати користувача
Перша зустріч IPrincipal
іIIdentity
public interface IPrincipal
{
IIdentity Identity { get; }
bool IsInRole(string role);
}
public interface IIdentity
{
string AuthenticationType { get; }
bool IsAuthenticated { get; }
string Name { get; }
}
IPrincipal
і IIdentity
представляє користувача та ім'я користувача. Вікіпедія потішить вас, якщо "Основний" звучить дивно .
Важливо усвідомити, чи отримуєте ви це IHttpContextAccessor.HttpContext.User
, ControllerBase.User
чи ControllerBase.HttpContext.User
отримуєте ви об'єкт, який гарантовано є ClaimsPrincipal
об'єктом, який реалізуєтьсяIPrincipal
.
Немає іншого типу Користувачів, яким ASP.NET зараз користується User
(але це не означає, що інші, які ще щось не вдалося реалізувати IPrincipal
).
Тож якщо у вас є щось, що має залежність від "поточного імені користувача", яке ви хочете зробити ін'єкційним, вам слід вводити ін'єкцію, IPrincipal
а точно - ні IHttpContextAccessor
.
Важливо: не витрачайте час на введення ін'єкцій IPrincipal
безпосередньо своєму контролеру чи метод дій - з тих пір це безглуздоUser
він уже доступний для вас.
В startup.cs
:
// Inject IPrincipal
services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);
Потім у ваш об’єкт DI, який потребує користувача, якого ви просто введете, IPrincipal
щоб отримати поточного користувача.
Найголовніше тут, якщо ви робите одиничні тести, вам не потрібно надсилати HttpContext
, а потрібно лише знущатися над тим, що представляє, IPrincipal
що може бути ClaimsPrincipal
.
Ще одна важлива річ, в якій я не впевнений на 100%. Якщо вам потрібно отримати доступ до фактичних претензій, до ClaimsPrincipal
яких потрібно IPrincipal
звернутись ClaimsPrincipal
. Це добре, оскільки ми знаємо на 100%, що під час виконання це саме такий тип (оскільки це HttpContext.User
є). Насправді мені подобається просто робити це в конструкторі, оскільки я вже точно знаю, що хтось IPrincipal
будеClaimsPrincipal
.
Якщо ви знущаєтесь, просто створіть ClaimsPrincipal
безпосередньо та передайте їх усім, що потрібно IPrincipal
.
Точно чому немає інтерфейсу, IClaimsPrincipal
я не впевнений. Я припускаю, що MS вирішила, що ClaimsPrincipal
це просто спеціалізована «колекція», яка не гарантує інтерфейс.