Setting up JWT and Identity Authorization/Authentication in ASP .NET Core
Alexandru Bucur
Posted on April 2, 2018
Continuing my foray into ASP .NET Core, and making sure I get outside my comfort zone, I got into the situation that I want to be able to easily access the logged in user information in my API request.
There are several versions available online, some unfortunately out of date (mostly because ASP .NET Core 2.0 is relatively new and things changed significantly in Identity between 1.0 and 2.0).
First version I stumbled upon recommended extending the IHttpContextAccessor. In case you don't know, in C# you can use a custom extension method to implement your own extensions to core libraries.
The code in my nativity looked like:
public static class IHttpContextAccessorExtension
{
public static string CurrentUser(
this IHttpContextAccessor httpContextAccessor
) {
return httpContextAccessor.HttpContext.User.FindFirst(JwtRegisteredClaimNames.Sub).Value;
}
}
Technically, that returns the user.Id since that's what my Claim definition specified. (ignore the fact that I only have one of the 'important' tokens)
var claims = new[] {
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Sub, user.Id),
};
Because of the fact that Microsoft 'knows' best (yes all separate links, I promise I'll make a docs pull request) we need to add System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
in our Startup.cs
/ ConfigureServices
(easiest is to just dump it at the top) in order to avoid the automatic conversion of the sub type to ClaimTypes.NameIdentifier
.
For some reason this is not improved in 2.0 even if it was a good occasion since it broke backwards compatibility (hoping to have this in 2.1 since the recent blog post suggested that 2.1 will not follow SemVer and could introduce breaking changes).
That being changed you can then redefine the UserIdClaimType
to use the Jwt claim.
services.AddIdentity<User, IdentityRole>(options =>
{
...
options.ClaimsIdentity.UserIdClaimType = JwtRegisteredClaimNames.Sub;
})
To be honest, I understand why this got ignored, because most of the time, your CurrentUser method would most likely look like:
public static class IHttpContextAccessorExtension
{
public static async Task<User> CurrentUser(
this IHttpContextAccessor httpContextAccessor,
UsersService users
)
{
return await users.UserManager.GetUserAsync(httpContextAccessor.HttpContext.User);
}
}
This works even if you don't reset the Claim handling since behind the scenes it does the transformation for you into ClaimTypes.NameIdentifier
. I'm not a big fan since even if convention over configuration is nice to have, this is a bit too magical for me since it also does a claim type conversion.
Now, as an alternative you could always just call the GetUserAsync
method on your UserManager
directly inside the controller because you have direct access to HttpContext.User
(or this.User
, again I like it a bit more explicit).
public async Task<IActionResult> Index()
{
// _users is my injected service that contains the UserManager
var currentUser = _users.UserManager.GetUserAsync(HttpContext.User);
}
How are you guys handling this ? Anything that I should keep in mind as best practice ?
Posted on April 2, 2018
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.