【问题标题】:Get userId from JWT on all Controller methods?在所有 Controller 方法上从 JWT 获取 userId?
【发布时间】:2018-11-07 20:46:31
【问题描述】:

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

这是有效的。如果我在 Bearer 标头中通过 JWT,我会得到 200。如果我未能通过 JWT,我会得到 401。一切正常。在我的 JWT 中,我在授权时将用户 ID 存储在“UserId”字段中。

var claimsdata = new[] {
                    new Claim("UserId", user.Id.ToString()),

然后我有一个扩展方法:

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;
        }

在我的控制器方法中,使用“授权”,我经常需要用户的 ID。所以我调用了我的 GetUserId 方法。这行得通。但是,我不确定这是否是从令牌中获取 Id 的最佳方式。

int.TryParse(User.GetUserId(), out _userId);

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

我在这里做对了吗?

【问题讨论】:

    标签: c# .net asp.net-core jwt


    【解决方案1】:
    var authenticatedUser = User.Identities.Select(c => c.Claims).ToArray()[0].ToArray()[0];
    
    var userid = await userManager.FindByNameAsync(authenticatedUser['email']).Id;
    

    【讨论】:

    • 欢迎堆栈溢出。也许你可以看看markdown help 来改进你的答案。
    • 帖子包含的细节太少。请在上面的评论中添加一些解释并使用降价帮助改进格式
    【解决方案2】:

    你也可以使用

    扩展方法

    喜欢这个

    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);
    }
    

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

    [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);
       }     
    }
    

    希望对你有帮助

    【讨论】:

    • 谢谢。这个答案实际上对我来说更有意义。不知道为什么使用控制器基类被更多人投票赞成。用户 ID 存储在用户声明中,因此扩展方法将允许您从用户对象访问用户 ID。我认为这更有意义,因为用户 ID 与用户对象相关。它与控制器无关。因此,您编写扩展方法,然后在每个控制器上添加一个引用以使用扩展方法。
    【解决方案3】:

    首先,我使用IHttpContextAccessor 注入创建IUserProvider 接口,以便在单元测试中模拟这些接口。

       public interface IUserProvider
       {
            string GetUserId();
       }
    

    比实现是

        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;
            }
        }
    

    因此您可以在控制器中使用接口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();
                }
            }
         }
    

    【讨论】:

      【解决方案4】:

      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);
          }
      }
      

      所有控制器都继承自this,现在所有控制器都可以访问UserId

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-13
        • 2012-05-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多