Muszę powiedzieć, że byłem dość zaskoczony, że HttpContext ma wartość null w konstruktorze. Jestem pewien, że to ze względu na wydajność. Potwierdziliśmy, że użycie w IPrincipalsposób opisany poniżej powoduje wstrzyknięcie go do konstruktora. Zasadniczo robi to samo, co zaakceptowana odpowiedź, ale w bardziej interfejsowy sposób.
Dla każdego, kto szuka tego pytania i szuka odpowiedzi na ogólne pytanie „Jak zdobyć aktualnego użytkownika?” możesz uzyskać Userbezpośredni dostęp z Controller.User. Ale możesz to zrobić tylko wewnątrz metod akcji (zakładam, że kontrolery działają nie tylko z HttpContexts i ze względu na wydajność).
Jeśli jednak potrzebujesz tego w konstruktorze (tak jak zrobił to OP) lub potrzebujesz stworzyć inne obiekty do wstrzyknięcia, które wymagają bieżącego użytkownika, poniższe jest lepszym podejściem:
Wstrzyknij IPrincipal, aby pobrać użytkownika
Najpierw spotkaj się IPrincipaliIIdentity
public interface IPrincipal
{
IIdentity Identity { get; }
bool IsInRole(string role);
}
public interface IIdentity
{
string AuthenticationType { get; }
bool IsAuthenticated { get; }
string Name { get; }
}
IPrincipali IIdentityreprezentuje użytkownika i nazwę użytkownika. Wikipedia pocieszy Cię, jeśli hasło „Principal” brzmi dziwnie .
Ważne jest, aby uświadomić sobie, że to, czy je dostać od IHttpContextAccessor.HttpContext.User, ControllerBase.Userczy ControllerBase.HttpContext.Userjesteś coraz obiekt, który jest gwarantowany być ClaimsPrincipalobiekt, który implementujeIPrincipal .
W tej chwili nie ma innego typu użytkownika, którego ASP.NET używa User(ale to nie znaczy, że inny nie mógłby zaimplementować czegoś innego IPrincipal).
Więc jeśli masz coś, co ma zależność od `` aktualnej nazwy użytkownika '', którą chcesz wstrzyknąć, powinieneś wstrzykiwać, IPrincipala na pewno nie IHttpContextAccessor.
Ważne: nie trać czasu na wstrzykiwanie IPrincipalbezpośrednio do kontrolera lub metody akcji - jest to bezcelowe, ponieważ Userjest już tam dostępne.
W startup.cs:
// Inject IPrincipal
services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);
Następnie w twoim obiekcie DI, który potrzebuje użytkownika, którego po prostu wstrzykujesz, IPrincipalaby pobrać bieżącego użytkownika.
Najważniejsze jest to, że jeśli robisz testy jednostkowe, nie musisz wysyłać HttpContext, a jedynie kpić z czegoś, IPrincipal co reprezentuje to, co może byćClaimsPrincipal .
Jedna bardzo ważna rzecz, której nie jestem pewien w 100%. Jeśli chcesz uzyskać dostęp do rzeczywistych roszczeń ClaimsPrincipal, musisz przesłać IPrincipaldo ClaimsPrincipal. To jest w porządku, ponieważ wiemy w 100%, że w czasie wykonywania jest tego typu (ponieważ tak HttpContext.Userjest). Właściwie lubię to po prostu robić w konstruktorze, ponieważ już wiem na pewno, że każdy IPrincipal będzie ClaimsPrincipal.
Jeśli robisz kpiny, po prostu utwórz ClaimsPrincipalbezpośrednio i przekaż to do dowolnego ujęcia IPrincipal.
Dokładnie dlaczego nie ma interfejsu, bo IClaimsPrincipalnie jestem pewien. Zakładam, że MS zdecydowało, że ClaimsPrincipalto tylko wyspecjalizowana „kolekcja”, która nie gwarantuje interfejsu.