从JWT获取所有Controller方法的userId?

Cra*_*aig 8 .net c# jwt asp.net-core

我正在创建一个使用JWT进行身份验证和授权的Core 2.0 Web API项目.我想要保护的控制器方法都使用Authorize属性进行修饰.

这很有效.如果我在Bearer标题中传递JWT,我得到200.如果我没有通过JWT,我得到401.所有工作.在我的JWT中,我在授权时将用户ID存储在'UserId'字段中.

var claimsdata = new[] {
                    new Claim("UserId", user.Id.ToString()),
Run Code Online (Sandbox Code Playgroud)

然后我有一个扩展方法:

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;
        }
Run Code Online (Sandbox Code Playgroud)

在我的控制器方法中,使用'Authorize',我经常需要用户的ID.所以我调用了我的GetUserId方法.这有效.但是,我不确定这是否是从令牌获取Id的最佳方式.

int.TryParse(User.GetUserId(), out _userId);
Run Code Online (Sandbox Code Playgroud)

我需要在所有控制器上使用该代码.我不能在构造函数中做到这一点,因为我认为这是错误的.

我在这做对了吗?

Hes*_*ehr 12

ControllerBase包含User属性类型的属性ClaimsPrincipal

您可以通过User.Claims而无需访问用户声明IPrincipal

创建一个包含GetUserId方法的基本控制器protected

public abstract class BaseController : Controller
{        
    protected int GetUserId()
    {
        return int.Parse(this.User.Claims.First(i => i.Type == "UserId").Value);
    }
}
Run Code Online (Sandbox Code Playgroud)

并且所有控制器都继承此形式,现在所有控制器都可以访问 UserId


小智 10

首先,我创建了IUserProvider带有IHttpContextAccessor注入的接口,以便在单元测试中为这些接口进行模拟。

   public interface IUserProvider
   {
        string GetUserId();
   }
Run Code Online (Sandbox Code Playgroud)

比实施是

    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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

所以你可以IUserProvider在你的控制器中使用接口而无需继承

    [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();
            }
        }
     }
Run Code Online (Sandbox Code Playgroud)


Akb*_*ari 5

你也可以使用

扩展方法

像这样

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);
}
Run Code Online (Sandbox Code Playgroud)

并像这样在您的控制器中实现

[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);
   }     
}
Run Code Online (Sandbox Code Playgroud)

我希望它会帮助你