Я должен сказать, что был очень удивлен, что HttpContext имеет значение null внутри конструктора. Я уверен, что это из соображений производительности. Подтвердили, что при использовании, IPrincipal
как описано ниже, он вводится в конструктор. По сути, он делает то же самое, что и принятый ответ, но более интерфейсным способом.
Для тех, кто нашел этот вопрос и ищет ответ на общий вопрос «Как получить текущего пользователя?» вы можете просто получить доступ User
прямо из Controller.User
. Но вы можете делать это только внутри методов действий (я предполагаю, потому что контроллеры работают не только с HttpContexts и по соображениям производительности).
Однако - если вам это нужно в конструкторе (как это сделал OP) или вам нужно создать другие инъекционные объекты, которым нужен текущий пользователь, то ниже будет лучший подход:
Внедрить 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
это просто специализированная «коллекция», для которой не нужен интерфейс.