I am trying to implement Jwt Authentication for my application and so far I have managed to generate the token and when I decoded it, it looks fine. However, when I use Postman to try to access areas of my code that is for Authorized only, I get an UnAuthorized error. I have discovered that its because of a setting in the Startup.cs.
Startup.cs
var key = Encoding.ASCII.GetBytes(Configuration["JwtAuthentication:SecurityKey"]);
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidIssuer = Configuration["JwtAuthentication:Issuer"],
ValidateIssuer = true,
ValidateLifetime = true,
ValidateAudience = true
};
});
If I set ValidateIssuer to false, I can get access to the [Authorized] controller, otherwise it will block me from it. Also, ValidateLifeTime doesn't seem to work for me. It will continue to show the result even though the token has expired.
This is how I generate my token in another class
public class GenerateToken : Controller
{
private IConfiguration configuration;
public GenerateToken(IConfiguration configuration)
{
this.configuration = configuration;
}
public String Generate(GenerateTokenViewModel Input)
{
var tokenHandler = new JwtSecurityTokenHandler();
List<Claim> claims = new List<Claim>();
claims.Add(new Claim("UserName", Input.User.UserName));
claims.Add(new Claim("Email", Input.User.Email));
claims.Add(new Claim("PhoneNumber", Input.User.PhoneNumber));
claims.Add(new Claim("FirstName", Input.User.FirstName));
claims.Add(new Claim("LastName", Input.User.LastName));
claims.Add(new Claim("Id", Input.User.Id));
foreach (var item in Input.Roles)
{
var currentItem = new UserRoleDetailsViewModel
{
Id = item.Id,
Name = item.Name,
ApplicationId = item.ApplicationId,
ApplicationName = item.ApplicationName
};
var convertedItem = JsonConvert.SerializeObject(currentItem);
claims.Add(new Claim("Roles", convertedItem));
}
var key = Encoding.ASCII.GetBytes(configuration["JwtAuthentication:SecurityKey"]);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Issuer = configuration["JwtAuthentication:Issuer"],
Audience = configuration["JwtAuthentication:Audience"],
IssuedAt = DateTime.UtcNow,
NotBefore = DateTime.UtcNow,
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var output = tokenHandler.WriteToken(token);
return output;
}
}
I'm not sure what I can do to solve it. Alternatively, is there a guide to generating and validating jwt for .net core 2.1?
EDIT:
Added Controller
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class AccountsController : ControllerBase
{
private AccountsData accountsData;
private readonly ILogger<AccountsController> logger;
private UserRolesData userRolesData;
private GenerateToken generateToken;
public AccountsController(ILogger<AccountsController> logger, GenerateToken generateToken, AccountsData accountsData, UserRolesData userRolesData)
{
this.accountsData = accountsData;
this.logger = logger;
this.userRolesData = userRolesData;
this.generateToken = generateToken;
}
[HttpGet]
[AllowAnonymous]
[Route("Item")]
public ActionResult Item()
{
return Ok("test");
}
[HttpGet]
[Route("GetThis")]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2" };
}
[HttpPost]
[AllowAnonymous]
[Route("Authenticate")]
public ActionResult Authenticate([FromBody]AccountsDto Input)
{
LoginViewModel lvm = new LoginViewModel
{
Email = Input.Email,
Password = Input.Password
};
var user = accountsData.Authenticate(lvm);
var token = "";
if(user == null)
{
return NotFound(LoggingGlobals.NotFound);
}
else
{
var roles = userRolesData.GetUserRoles(user.Id);
GenerateTokenViewModel gtvm = new GenerateTokenViewModel
{
User = user,
Roles = roles
};
token = generateToken.Generate(gtvm);
}
return Ok(token);
}
}