Je dois dire que j'ai été assez surpris que HttpContext soit nul à l'intérieur du constructeur. Je suis sûr que c'est pour des raisons de performance. Avoir confirmé que l'utilisation IPrincipal
comme décrit ci-dessous l'injecte dans le constructeur. Il fait essentiellement la même chose que la réponse acceptée, mais d'une manière plus interface.
Pour tous ceux qui trouvent cette question à la recherche d'une réponse au générique "Comment obtenir l'utilisateur actuel?" vous pouvez simplement accéder User
directement à partir de Controller.User
. Mais vous ne pouvez le faire qu'à l'intérieur des méthodes d'action (je suppose que les contrôleurs ne fonctionnent pas uniquement avec HttpContexts et pour des raisons de performances).
Cependant - si vous en avez besoin dans le constructeur (comme OP l'a fait) ou si vous devez créer d'autres objets injectables qui ont besoin de l'utilisateur actuel, alors la solution ci-dessous est une meilleure approche:
Injectez IPrincipal pour obtenir l'utilisateur
Première rencontre IPrincipal
etIIdentity
public interface IPrincipal
{
IIdentity Identity { get; }
bool IsInRole(string role);
}
public interface IIdentity
{
string AuthenticationType { get; }
bool IsAuthenticated { get; }
string Name { get; }
}
IPrincipal
et IIdentity
représente l'utilisateur et le nom d'utilisateur. Wikipedia vous réconfortera si «Principal» semble étrange .
Il est important de se rendre compte que si vous l' obtenez à partir IHttpContextAccessor.HttpContext.User
, ControllerBase.User
ou ControllerBase.HttpContext.User
vous faire un objet qui est garanti d'être un ClaimsPrincipal
objet qui met en œuvreIPrincipal
.
Il n'y a aucun autre type d'utilisateur utilisé par ASP.NET pour User
le moment (mais cela ne veut pas dire que quelque chose d'autre ne pourrait pas être implémenté IPrincipal
).
Donc, si vous avez quelque chose qui a une dépendance du «nom d'utilisateur actuel» que vous voulez injecter, vous devriez l'injecter IPrincipal
et certainement pas IHttpContextAccessor
.
Important: ne perdez pas de temps à injecter IPrincipal
directement dans votre manette ou votre méthode d'action - c'est inutile car User
vous y êtes déjà disponible.
Dans startup.cs
:
// Inject IPrincipal
services.AddTransient<IPrincipal>(provider => provider.GetService<IHttpContextAccessor>().HttpContext.User);
Ensuite, dans votre objet DI qui a besoin de l'utilisateur que vous venez d'injecter IPrincipal
pour obtenir l'utilisateur actuel.
La chose la plus importante ici est que si vous faites des tests unitaires, vous n'avez pas besoin d'envoyer un HttpContext
, mais seulement de vous moquer de quelque chose qui représente IPrincipal
ce qui peut simplement être ClaimsPrincipal
.
Une chose supplémentaire importante dont je ne suis pas sûr à 100%. Si vous avez besoin d'accéder aux demandes d' indemnités de ClaimsPrincipal
vous devez convertir IPrincipal
à ClaimsPrincipal
. C'est très bien car nous savons à 100% qu'au moment de l'exécution, c'est de ce type (puisque c'est ce qui HttpContext.User
est). En fait, j'aime faire cela dans le constructeur car je sais déjà avec certitude que tout IPrincipal
sera un fichier ClaimsPrincipal
.
Si vous vous moquez, créezClaimsPrincipal
simplement un directement et transmettez-le à tout ce qui prend IPrincipal
.
Exactement pourquoi il n'y a pas d'interface pour IClaimsPrincipal
je ne suis pas sûr. Je suppose que MS a décidé que ce ClaimsPrincipal
n'était qu'une «collection» spécialisée qui ne justifiait pas une interface.