Reputation: 5084
This is my first time attempting to use Asp.Net Core Web Api. I have everything working including authentication and jwt token creation and verification. What I am trying to do is extract the user information that is in the token and use some of it when posting data to the database. I create the token like this:
public string NewToken(string ApiKey, ICAN_Context context)
{
var user = context.TblUserLogins.Where(x => x.ApiKey == ApiKey).FirstOrDefault();
int? CompanyId = context.TblEmployeeCompanies.Where(x => x.EmployeeId == user.EmployeeId).Select(x => x.CompanyId).FirstOrDefault();
var identity = new ClaimsIdentity();
identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName));
identity.AddClaim(new Claim("CompanyId", CompanyId.ToString(), ClaimValueTypes.Integer32));
identity.AddClaim(new Claim("EmployeeCompanyId", user.EmployeeCompanyId.ToString(), ClaimValueTypes.Integer32 ));
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(identity),
Expires = DateTime.UtcNow.AddMinutes(60),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(secretKey), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var jwtString = tokenHandler.WriteToken(token);
return jwtString;
}
I verify the token using a "filter":
public void OnAuthorization(AuthorizationFilterContext context)
{
var tokenManager = (ITokenManager)context.HttpContext.RequestServices.GetService(typeof(ITokenManager));
var result = true;
if(!context.HttpContext.Request.Headers.ContainsKey("Authorization"))
{
result = false;
}
string token = string.Empty;
if(result)
{
token = context.HttpContext.Request.Headers.First(x=>x.Key == "Authorization").Value;
try
{
var claimPrinciple = tokenManager.VerifyToken(token);
}
catch(Exception ex)
{
result = false;
context.ModelState.AddModelError("Unauthorized", ex.ToString());
}
}
if(!result)
{
context.Result = new UnauthorizedObjectResult(context.ModelState);
}
}
I have no problem retrieving the claims info from the token, my question is how do I get the claims from the token in my controller method?
I want to be able to retrieve its values in my methods something like this:
[HttpPost]
[Route("~/api/entity/department")]
public IActionResult CreateDepartment([FromBody] TblCompanyDepartmentsXlu department)
{
var identity = (ClaimsIdentity)User.Identity;
_context.Departments.Add(department);
_context.SaveChanges();
return Ok("Department created successfully!");
}
I also tried this from StackOverflow:
public static ClaimsPrincipal VerifyToken(string jwtToken)
{
TokenManager tokenManager = new TokenManager();
SecurityToken validatedToken;
TokenValidationParameters validationParameters = new TokenValidationParameters();
validationParameters.ValidateLifetime = true;
validationParameters.IssuerSigningKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(tokenManager.secretKey);
validationParameters.ValidateAudience = false;
validationParameters.ValidateIssuer = false;
ClaimsPrincipal principal = new JwtSecurityTokenHandler().ValidateToken(jwtToken, validationParameters, out validatedToken);
return principal;
}
[HttpGet]
[Route("~/api/entity/GetEmployees")]
public List<TblEmployees> GetEmployees()
{
var identity = HttpContext.User.Identity as ClaimsIdentity;
if (identity != null)
{
IEnumerable<Claim> claims = identity.Claims;
}
var employees = _context.Employees.ToList();
return employees;
}
but identity.Claims
is ALWAYS 0.
I am able to retrieve the claims right after verifying the token:
var claimPrinciple = TokenManager.VerifyToken(token);
I am able to retrieve the claims info here
var claims = claimPrinciple.Identities.First().Claims.ToList();
int? CompanyId = Convert.ToInt32(claims.Where(x => x.Type == "CompanyId").FirstOrDefault().Value);
int EmployeeCompanyId = Convert.ToInt32(claims.Where(x => x.Type == "EmployeeCompanyId").FirstOrDefault().Value);
But I am unable to retrieve them in the controller.
Upvotes: 1
Views: 2605
Reputation: 5084
@Klekmek was correct. All I needed to do was use the built-in JWT token functionality (which I didn't know existed). I removed the AuthenticationFilter and added this to my startup: To the ConfigureServices section:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(jwt => {
var key = Encoding.ASCII.GetBytes(Configuration["JwtConfig:Secret"]);
jwt.SaveToken = true;
jwt.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateLifetime = true,
ValidateIssuer = false,
ValidateAudience = false
};
});
And the Configure section:
app.UseAuthentication();
After adding that, this worked:
var identity = HttpContext.User.Identity as ClaimsIdentity;
Upvotes: -1
Reputation: 129
//startup.cs dotnet 6.0 :
builder.Services.AddHttpContextAccessor();
.
.
.
//where you want to use the IHttpContextAccessor :
//For example in user repository :
private readonly IHttpContextAccessor _httpContextAccessor;
public UserRepository(IHttpContextAccessor httpContextAccessor) =>
_httpContextAccessor = httpContextAccessor;
public void LogCurrentUser()
{
var username = _httpContextAccessor.HttpContext.User.Identity.Name;
// ...
}
Upvotes: 2