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

时间:2018-05-29 08:56:53

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

我正在创建一个使用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;
        }

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

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

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

我在这里做对了吗?

4 个答案:

答案 0 :(得分:9)

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

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

答案 1 :(得分:2)

还可以使用

扩展方法

像这样


var retrofitPart = module {
    single<KakaoSearchService> {
        Retrofit.Builder()
            .baseUrl("https://dapi.kakao.com")
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(KakaoSearchService::class.java)
    }
}


var adapterPart = module {
    factory {
        MainSearchRecyclerViewAdapter()
    }
}

var modelPart = module {
    factory<DataModel> {
        DataModelImpl(get())
    }
}

var viewModelPart = module {
    viewModel {
        MainViewModel(get())
    }
}

var myDiModule = listOf(retrofitPart, adapterPart, modelPart, viewModelPart)

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

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

我希望它将对您有帮助

答案 2 :(得分:1)

首先,我通过注入IUserProvider创建IHttpContextAccessor接口,以在单元测试中为这些接口进行模拟。

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

答案 3 :(得分:-4)

var authenticatedUser = User.Identities.Select(c => c.Claims).ToArray()[0].ToArray()[0];

var userid = await userManager.FindByNameAsync(authenticatedUser['email']).Id;