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 IPrincipal
sposó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ć User
bezpoś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ę IPrincipal
iIIdentity
public interface IPrincipal
{
IIdentity Identity { get; }
bool IsInRole(string role);
}
public interface IIdentity
{
string AuthenticationType { get; }
bool IsAuthenticated { get; }
string Name { get; }
}
IPrincipal
i IIdentity
reprezentuje 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.User
czy ControllerBase.HttpContext.User
jesteś coraz obiekt, który jest gwarantowany być ClaimsPrincipal
obiekt, 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ć, IPrincipal
a na pewno nie IHttpContextAccessor
.
Ważne: nie trać czasu na wstrzykiwanie IPrincipal
bezpośrednio do kontrolera lub metody akcji - jest to bezcelowe, ponieważ User
jest 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, IPrincipal
aby 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ć IPrincipal
do ClaimsPrincipal
. To jest w porządku, ponieważ wiemy w 100%, że w czasie wykonywania jest tego typu (ponieważ tak HttpContext.User
jest). 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 ClaimsPrincipal
bezpośrednio i przekaż to do dowolnego ujęcia IPrincipal
.
Dokładnie dlaczego nie ma interfejsu, bo IClaimsPrincipal
nie jestem pewien. Zakładam, że MS zdecydowało, że ClaimsPrincipal
to tylko wyspecjalizowana „kolekcja”, która nie gwarantuje interfejsu.