Devo dire che sono rimasto piuttosto sorpreso dal fatto che HttpContext sia nullo all'interno del costruttore. Sono sicuro che sia per motivi di prestazioni. Ho confermato che l'utilizzo IPrincipal
come descritto di seguito lo fa iniettare nel costruttore. Sta essenzialmente facendo lo stesso della risposta accettata, ma in un modo più interfacciato.
Per chiunque trovi questa domanda cercando una risposta alla generica "Come ottenere l'utente corrente?" puoi semplicemente accedere User
direttamente daController.User
. Ma puoi farlo solo all'interno dei metodi di azione (presumo perché i controller non vengono eseguiti solo con HttpContexts e per motivi di prestazioni).
Tuttavia, se ne hai bisogno nel costruttore (come ha fatto OP) o hai bisogno di creare altri oggetti iniettabili che richiedono l'utente corrente, il seguente è un approccio migliore:
Iniettare IPrincipal per ottenere user
Primo incontro IPrincipal
eIIdentity
public interface IPrincipal
{
IIdentity Identity { get; }
bool IsInRole(string role);
}
public interface IIdentity
{
string AuthenticationType { get; }
bool IsAuthenticated { get; }
string Name { get; }
}
IPrincipal
e IIdentity
rappresenta l'utente e il nome utente. Wikipedia ti consolerà se "Preside" suona strano .
Importante rendersi conto che se si ottiene da IHttpContextAccessor.HttpContext.User
, ControllerBase.User
o ControllerBase.HttpContext.User
che stai ricevendo un oggetto che è garantito per essere un ClaimsPrincipal
oggetto che implementaIPrincipal
.
Non c'è nessun altro tipo di utente che ASP.NET utilizza per User
ora, (ma questo non vuol dire altro che qualcos'altro non potrebbe implementare IPrincipal
).
Quindi, se hai qualcosa che ha una dipendenza del "nome utente corrente" che desideri venga iniettato, dovresti farlo IPrincipal
e sicuramente no IHttpContextAccessor
.
Importante: non perdere tempo a iniettare IPrincipal
direttamente nel controller o nel metodo di azione: da allora è inutileUser
è già disponibile.
In startup.cs
:
// Inject IPrincipal
services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);
Quindi nel tuo oggetto DI che ha bisogno dell'utente che hai appena iniettato IPrincipal
per ottenere l'utente corrente.
La cosa più importante qui è che se stai facendo unit test non è necessario inviare un HttpContext
, ma devi solo deridere qualcosa che rappresenta IPrincipal
che può essere ClaimsPrincipal
.
Una cosa importante in più di cui non sono sicuro al 100%. Se avete bisogno di accedere ai crediti effettivi da ClaimsPrincipal
dovete getto IPrincipal
a ClaimsPrincipal
. Questo va bene poiché sappiamo al 100% che in fase di esecuzione è di quel tipo (poiché è quello che HttpContext.User
è). In realtà mi piace farlo solo nel costruttore poiché so già per certo che qualsiasi IPrincipal
sarà un fileClaimsPrincipal
.
Se stai prendendo in giro, creaClaimsPrincipal
semplicemente un direttamente e passalo a qualsiasi cosa IPrincipal
.
Esattamente il motivo per cui non esiste un'interfaccia per IClaimsPrincipal
non ne sono sicuro. Presumo che MS abbia deciso che ClaimsPrincipal
era solo una "raccolta" specializzata che non garantisce un'interfaccia.