Я должен сказать, что был очень удивлен, что 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это просто специализированная «коллекция», для которой не нужен интерфейс.