Reputation: 65
I have an MVC application and one exposed API Endpoint. I authenticated my MVC application with the defaults from Identity Core, I use User.FindFirstValue(ClaimTypes.NameIdentifier)
to find if a certain user is logged in, etc.
For my API Endpoint, I use JWT authentication below is the configuration code for JWT:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(jwt =>
{
var key = Encoding.ASCII.GetBytes(Configuration["Jwt:Secret"]);
jwt.SaveToken = true;
jwt.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
RequireExpirationTime = false,
ValidateLifetime = true
};
});
Here is the controller for token request:
[HttpPost]
[Route("token")]
public async Task<IActionResult> Token([FromBody] UserLoginRequest user)
{
if (ModelState.IsValid)
{
var existingUser = await _userManager.FindByEmailAsync(user.Email);
if (existingUser == null)
{
return BadRequest();
}
var isCorrect = await _userManager.CheckPasswordAsync(existingUser, user.Password);
if (isCorrect)
{
var jwtToken = _identityService.GenerateJwtToken(existingUser);
return Ok(new RegistrationResponse()
{
Result = true,
Token = jwtToken
});
}
else
{
return BadRequest();
}
}
return BadRequest();
}
On my MVC controllers, I use [Authorize]
On my API Endpoint i use [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
My GenerateJWTToken
method:
public string GenerateJwtToken(IdentityUser user)
{
var jwtTokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_jwtConfig.Secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim("Id", user.Id),
new Claim(JwtRegisteredClaimNames.Sub, user.Email),
new Claim(JwtRegisteredClaimNames.Email, user.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
}),
Expires = DateTime.UtcNow.AddHours(6),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha512Signature)
};
var token = jwtTokenHandler.CreateToken(tokenDescriptor);
var jwtToken = jwtTokenHandler.WriteToken(token);
return jwtToken;
}
}
But obviously, this solution fails to function because once I start my MVC Application and try to log in, I get redirected back to Index and I'm still unauthorized. And vice versa with the API, when I make a Postman call, I get the token, and when I try to call my Bookmarks Controller to query user's bookmarks I get zero, although there are bookmarks for that certain user.
Any ideas on how could I make this work would be welcomed.
Upvotes: 1
Views: 1004
Reputation: 216
In the controller for your token request, try adding [AllowAnonymous], like this:
[AllowAnonymous]
[HttpPost]
[Route("token")]
public async Task<IActionResult> Token([FromBody] UserLoginRequest user)
{
// snip...
}
Upvotes: 1
Reputation: 388
Inside my JWT Token Generator, I get details of the user I would like to store as claims such as the username, which can be used to identify the user.
public static class JwtTokenExtensions
{
/// <summary>
/// Generates a JWT Bearer token containing the users email
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
public static string GenerateJwtToken(this Identity user)
{
// Set our token claims
Claim[] claims = {
// Unique ID for this token
new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")),
new(JwtRegisteredClaimNames.Email, user.Email),
// The username using the Identity name so it fills out the HttpContext.User.Identity.Name value
new(ClaimsIdentity.DefaultNameClaimType, user.UserName),
// Add user Id so that UserManager.GetUserAsync can find the user based on Id
new Claim(ClaimTypes.NameIdentifier, user.Id)
};
// Create the credentials used to generate the token
SigningCredentials credentials =
new SigningCredentials(SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:SecretKey"])),
SecurityAlgorithms.HmacSha256);
// Generate the Jwt Token that lasts for an hour before expiring
JwtSecurityToken token =
new JwtSecurityToken
(Configuration["Jwt:Issuer"],
Configuration["Jwt:Audience"],
claims:claims,
signingCredentials:credentials,
expires: DateTime.Now.AddHours(1));
// Return the generated token.
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
Inside the api controllers with JWT authorization, I can get the user via the HttpContext
var user = await _userManager.GetUserAsync(HttpContext.User);
Upvotes: 1