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 IPrincipalcome 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 Userdirettamente 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 IPrincipaleIIdentity
public interface IPrincipal
{
IIdentity Identity { get; }
bool IsInRole(string role);
}
public interface IIdentity
{
string AuthenticationType { get; }
bool IsAuthenticated { get; }
string Name { get; }
}
IPrincipale IIdentityrappresenta 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.Usero ControllerBase.HttpContext.Userche stai ricevendo un oggetto che è garantito per essere un ClaimsPrincipaloggetto che implementaIPrincipal .
Non c'è nessun altro tipo di utente che ASP.NET utilizza per Userora, (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 IPrincipale sicuramente no IHttpContextAccessor.
Importante: non perdere tempo a iniettare IPrincipaldirettamente 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 ClaimsPrincipaldovete getto IPrincipala 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 IClaimsPrincipalnon ne sono sicuro. Presumo che MS abbia deciso che ClaimsPrincipalera solo una "raccolta" specializzata che non garantisce un'interfaccia.