Je crée un projet d'API Web Core 2.0 qui utilise JWT pour l'authentification et l'autorisation. Mes méthodes de contrôleur que je veux sécuriser sont toutes décorées avec l'attribut Authorize
.
Cela fonctionne. Si je passe le JWT dans l'en-tête Bearer, j'obtiens un 200. Si je ne réussis pas à passer le JWT, j'obtiens le 401. Tout fonctionne. Dans mon JWT, j'ai stocké l'ID utilisateur dans le champ 'UserId' lors de l'autorisation ..
var claimsdata = new[] {
new Claim("UserId", user.Id.ToString()),
J'ai ensuite une méthode d'extension:
public static string GetUserId(this IPrincipal user)
{
if (user == null)
return string.Empty;
var identity = (ClaimsIdentity)user.Identity;
IEnumerable<Claim> claims = identity.Claims;
return claims.FirstOrDefault(s => s.Type == "UserId")?.Value;
}
Sur ma méthode de contrôleur, avec "Autoriser", j'ai souvent besoin de l'ID de l'utilisateur. J'appelle donc ma méthode GetUserId. Cela marche. Cependant, je ne suis pas sûr que ce soit la meilleure façon d'obtenir l'ID du jeton.
int.TryParse(User.GetUserId(), out _userId);
J'ai besoin d'utiliser ce code sur tous les contrôleurs. Je ne peux pas le faire dans le constructeur, car ... c'est faux je pense.
Suis-je en train de faire la bonne chose ici?
ControllerBase
contient User
propriété de type ClaimsPrincipal
Vous pouvez accéder aux revendications des utilisateurs par User.Claims
et pas besoin de IPrincipal
Créez un contrôleur de base qui contient la méthode GetUserId
en tant que protected
public abstract class BaseController : Controller
{
protected int GetUserId()
{
return int.Parse(this.User.Claims.First(i => i.Type == "UserId").Value);
}
}
Et tous les contrôleurs héritent de cela, maintenant tous les contrôleurs peuvent accéder à UserId
Tout d'abord, je crée une interface IUserProvider
avec une injection IHttpContextAccessor
pour faire des simulations pour ces interfaces dans des tests unitaires.
public interface IUserProvider
{
string GetUserId();
}
Que la mise en œuvre est
public class UserProvider : IUserProvider
{
private readonly IHttpContextAccessor _context;
public UserProvider (IHttpContextAccessor context)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
}
public string GetUserId()
{
return _context.HttpContext.User.Claims
.First(i => i.Type == ClaimTypes.NameIdentifier).Value;
}
}
Vous pouvez donc utiliser l'interface IUserProvider
dans votre contrôleur sans héritage
[Authorize]
[ApiController]
public class MyController : ControllerBase
{
private readonly IUserProvider _userProvider;
public MyController(IUserProvider userProvider)
{
_userProvider = userProvider ?? throw new ArgumentNullException(nameof(userProvider ));
}
[HttpGet]
[Route("api/My/Something")]
public async Task<ActionResult> GetSomething()
{
try
{
var userId= _userProvider.GetUserId();
}
}
}
Vous pouvez également utiliser
Méthode d'extension
comme ça
public static long GetUserID(this ClaimsPrincipal User)
{
return long.Parse(User.Claims.First(i => i.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier").Value);
}
et mettre en œuvre dans votre contrôleur comme celui-ci
[HttpDelete("DeleteAddress")]
public async Task<IActionResult> DeleteAddress([FromQuery] long AddressID)
{
try
{
long userID = this.User.GetUserID();
await _addressService.Delete(userID, AddressID);
return Ok();
}
catch (Exception err)
{
return Conflict(err.Message);
}
}
J'espère que cela vous aidera