ASP.Net Core JWT Login not setting HttpContext.User.Claims
up vote
0
down vote
favorite
I have the following for my login code, and another method to retrieve the user ID in another call.
// POST: /api/Account/Login
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login([FromBody]LoginViewModel model)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByEmailAsync(model.Email);
if (user != null)
{
if (!await _userManager.IsEmailConfirmedAsync(user))
{
ModelState.AddModelError(string.Empty,
"You must have a confirmed email to log in.");
return BadRequest(Errors.AddErrorToModelState("Email", "You must have a confirmed email to log in.", ModelState));
}
}
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
// IS THIS NEEDED? --> // HttpContext.User = await _userClaimsPrincipalFactory.CreateAsync(user);
var tokens = _antiforgery.GetAndStoreTokens(HttpContext);
var identity = _jwtFactory.GenerateClaimsIdentity(model.Email, user.Id);
_logger.LogInformation(1, "User logged in.");
var jwt = await Tokens.GenerateJwt(identity, _jwtFactory, model.Email, _jwtOptions, new JsonSerializerSettings { Formatting = Formatting.Indented });
return new OkObjectResult(jwt);
}
if (result.RequiresTwoFactor)
{
//return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
}
if (result.IsLockedOut)
{
string message = "User account locked out.";
_logger.LogWarning(2, message);
return BadRequest(Errors.AddErrorToModelState("Email", message, ModelState));
}
if (result.IsNotAllowed)
{
string message = "User account is not allowed to sign in.";
_logger.LogWarning(2, message);
return BadRequest(Errors.AddErrorToModelState("Email", message, ModelState));
}
return BadRequest(Errors.AddErrorToModelState("", "Sign in failed.", ModelState));
}
return BadRequest(Errors.AddErrorToModelState("", "", ModelState));
}
public string GetUserId()
{
string username = string.Empty;
ClaimsPrincipal principal = HttpContext.User as ClaimsPrincipal;
if (HttpContext.User != null)
{
var id = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier);
if (id != null)
{
username = id.Value;
}
}
return username;
}
This is the code for GenerateJwt. (Are these fields standard? I see other fields being set in other code, such as in https://code-maze.com/authentication-aspnetcore-jwt-1/.)
public static async Task<string> GenerateJwt(ClaimsIdentity identity, IJwtFactory jwtFactory,string userName, JwtIssuerOptions jwtOptions, JsonSerializerSettings serializerSettings)
{
var response = new
{
id = identity.Claims.Single(c => c.Type == "id").Value,
auth_token = await jwtFactory.GenerateEncodedToken(userName, identity),
expires_in = (int)jwtOptions.ValidFor.TotalSeconds
}; // see GenerateEncodedToken pasted below.
return JsonConvert.SerializeObject(response, serializerSettings);
}
public async Task<string> GenerateEncodedToken(string userName, ClaimsIdentity identity)
{
var claims = new
{
new Claim(JwtRegisteredClaimNames.Sub, userName),
new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64),
identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Rol),
identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Id)
};
// Create the JWT security token and encode it.
var jwt = new JwtSecurityToken(
issuer: _jwtOptions.Issuer,
audience: _jwtOptions.Audience,
claims: claims,
notBefore: _jwtOptions.NotBefore,
expires: _jwtOptions.Expiration,
signingCredentials: _jwtOptions.SigningCredentials);
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
return encodedJwt;
}
These are the relevant lines in ConfigureServices.
// jwt wire up
// Get options from app settings
var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));
// Configure JwtIssuerOptions
services.Configure<JwtIssuerOptions>(options =>
{
options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)];
options.SigningCredentials = new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256);
});
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)],
ValidateAudience = true,
ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)],
ValidateIssuerSigningKey = true,
IssuerSigningKey = _signingKey,
RequireExpirationTime = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(configureOptions =>
{
configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
configureOptions.TokenValidationParameters = tokenValidationParameters;
configureOptions.SaveToken = true;
configureOptions.RequireHttpsMetadata = false;
});
// api user claim policy
services.AddAuthorization(options =>
{
options.AddPolicy("ApiUser", policy => policy.RequireClaim(Constants.Strings.JwtClaimIdentifiers.Rol, Constants.Strings.JwtClaims.ApiAccess));
});
// add identity
var builder = services.AddIdentity<AppUser, AppRole>(o =>
{
// configure identity options
o.Password.RequireDigit = false;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
o.Password.RequireNonAlphanumeric = false;
o.Password.RequiredLength = 6;
})
.AddSignInManager<SignInManager<AppUser>>()
.AddEntityFrameworkStores<AppIdentityDbContext>()
.AddDefaultTokenProviders();
I'm using the following to pass my token from Angular.
private authHeader(): HttpHeaders {
let headers = new HttpHeaders();
if (isPlatformBrowser(this.platformId)) {
headers = headers.set('Content-Type', 'application/json');
let authToken = this.windowRefService.nativeWindow.localStorage.getItem('auth_token');
headers = headers.set('Authorization', authToken);
headers = headers.set('X-XSRF-TOKEN', this.getCookie('XSRF-TOKEN'));
}
return headers;
}
protected jsonAuthRequestOptions = { headers: this.authHeader() };
public loggedInAs(): Observable<string> {
return this.http.post<any>(this.baseUrl + "api/Account/GetUserId", { } , this.jsonAuthRequestOptions)
.map(data => {
if (data) {
return data;
}
return '';
})
.catch(this.handleError);
}
Does JWT authentication automatically set HttpContext.User? Or do I have to do that explicitly?
My succeeding call fails. (User has no claims, though HttpContext.User is not null.) I don't know whether the problem is with relying on HttpContext.User, or whether there is something wrong with the token generation / consumption.
asp.net-core jwt
|
show 1 more comment
up vote
0
down vote
favorite
I have the following for my login code, and another method to retrieve the user ID in another call.
// POST: /api/Account/Login
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login([FromBody]LoginViewModel model)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByEmailAsync(model.Email);
if (user != null)
{
if (!await _userManager.IsEmailConfirmedAsync(user))
{
ModelState.AddModelError(string.Empty,
"You must have a confirmed email to log in.");
return BadRequest(Errors.AddErrorToModelState("Email", "You must have a confirmed email to log in.", ModelState));
}
}
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
// IS THIS NEEDED? --> // HttpContext.User = await _userClaimsPrincipalFactory.CreateAsync(user);
var tokens = _antiforgery.GetAndStoreTokens(HttpContext);
var identity = _jwtFactory.GenerateClaimsIdentity(model.Email, user.Id);
_logger.LogInformation(1, "User logged in.");
var jwt = await Tokens.GenerateJwt(identity, _jwtFactory, model.Email, _jwtOptions, new JsonSerializerSettings { Formatting = Formatting.Indented });
return new OkObjectResult(jwt);
}
if (result.RequiresTwoFactor)
{
//return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
}
if (result.IsLockedOut)
{
string message = "User account locked out.";
_logger.LogWarning(2, message);
return BadRequest(Errors.AddErrorToModelState("Email", message, ModelState));
}
if (result.IsNotAllowed)
{
string message = "User account is not allowed to sign in.";
_logger.LogWarning(2, message);
return BadRequest(Errors.AddErrorToModelState("Email", message, ModelState));
}
return BadRequest(Errors.AddErrorToModelState("", "Sign in failed.", ModelState));
}
return BadRequest(Errors.AddErrorToModelState("", "", ModelState));
}
public string GetUserId()
{
string username = string.Empty;
ClaimsPrincipal principal = HttpContext.User as ClaimsPrincipal;
if (HttpContext.User != null)
{
var id = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier);
if (id != null)
{
username = id.Value;
}
}
return username;
}
This is the code for GenerateJwt. (Are these fields standard? I see other fields being set in other code, such as in https://code-maze.com/authentication-aspnetcore-jwt-1/.)
public static async Task<string> GenerateJwt(ClaimsIdentity identity, IJwtFactory jwtFactory,string userName, JwtIssuerOptions jwtOptions, JsonSerializerSettings serializerSettings)
{
var response = new
{
id = identity.Claims.Single(c => c.Type == "id").Value,
auth_token = await jwtFactory.GenerateEncodedToken(userName, identity),
expires_in = (int)jwtOptions.ValidFor.TotalSeconds
}; // see GenerateEncodedToken pasted below.
return JsonConvert.SerializeObject(response, serializerSettings);
}
public async Task<string> GenerateEncodedToken(string userName, ClaimsIdentity identity)
{
var claims = new
{
new Claim(JwtRegisteredClaimNames.Sub, userName),
new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64),
identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Rol),
identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Id)
};
// Create the JWT security token and encode it.
var jwt = new JwtSecurityToken(
issuer: _jwtOptions.Issuer,
audience: _jwtOptions.Audience,
claims: claims,
notBefore: _jwtOptions.NotBefore,
expires: _jwtOptions.Expiration,
signingCredentials: _jwtOptions.SigningCredentials);
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
return encodedJwt;
}
These are the relevant lines in ConfigureServices.
// jwt wire up
// Get options from app settings
var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));
// Configure JwtIssuerOptions
services.Configure<JwtIssuerOptions>(options =>
{
options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)];
options.SigningCredentials = new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256);
});
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)],
ValidateAudience = true,
ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)],
ValidateIssuerSigningKey = true,
IssuerSigningKey = _signingKey,
RequireExpirationTime = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(configureOptions =>
{
configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
configureOptions.TokenValidationParameters = tokenValidationParameters;
configureOptions.SaveToken = true;
configureOptions.RequireHttpsMetadata = false;
});
// api user claim policy
services.AddAuthorization(options =>
{
options.AddPolicy("ApiUser", policy => policy.RequireClaim(Constants.Strings.JwtClaimIdentifiers.Rol, Constants.Strings.JwtClaims.ApiAccess));
});
// add identity
var builder = services.AddIdentity<AppUser, AppRole>(o =>
{
// configure identity options
o.Password.RequireDigit = false;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
o.Password.RequireNonAlphanumeric = false;
o.Password.RequiredLength = 6;
})
.AddSignInManager<SignInManager<AppUser>>()
.AddEntityFrameworkStores<AppIdentityDbContext>()
.AddDefaultTokenProviders();
I'm using the following to pass my token from Angular.
private authHeader(): HttpHeaders {
let headers = new HttpHeaders();
if (isPlatformBrowser(this.platformId)) {
headers = headers.set('Content-Type', 'application/json');
let authToken = this.windowRefService.nativeWindow.localStorage.getItem('auth_token');
headers = headers.set('Authorization', authToken);
headers = headers.set('X-XSRF-TOKEN', this.getCookie('XSRF-TOKEN'));
}
return headers;
}
protected jsonAuthRequestOptions = { headers: this.authHeader() };
public loggedInAs(): Observable<string> {
return this.http.post<any>(this.baseUrl + "api/Account/GetUserId", { } , this.jsonAuthRequestOptions)
.map(data => {
if (data) {
return data;
}
return '';
})
.catch(this.handleError);
}
Does JWT authentication automatically set HttpContext.User? Or do I have to do that explicitly?
My succeeding call fails. (User has no claims, though HttpContext.User is not null.) I don't know whether the problem is with relying on HttpContext.User, or whether there is something wrong with the token generation / consumption.
asp.net-core jwt
Are you callingservices.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(...
andapp.UseAuthentication();
inStartup.cs
?
– Albert
yesterday
Yes. services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(configureOptions => { configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)]; configureOptions.TokenValidationParameters = tokenValidationParameters; configureOptions.SaveToken = true; });
– Jonas Arcangel
yesterday
And did you set theapp.UseAuthentication()
onConfigure
method withinStartup.cs
file as well, before theUseMvc
? Double-check here
– Anderson Matos
yesterday
I also have app.UseAuthentication() as well as app.UseJwtTokenMiddleware() before UseMvc().
– Jonas Arcangel
yesterday
HttpContext.User exists, so I think it is getting authenticated. It's just that the Claims is empty.
– Jonas Arcangel
yesterday
|
show 1 more comment
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I have the following for my login code, and another method to retrieve the user ID in another call.
// POST: /api/Account/Login
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login([FromBody]LoginViewModel model)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByEmailAsync(model.Email);
if (user != null)
{
if (!await _userManager.IsEmailConfirmedAsync(user))
{
ModelState.AddModelError(string.Empty,
"You must have a confirmed email to log in.");
return BadRequest(Errors.AddErrorToModelState("Email", "You must have a confirmed email to log in.", ModelState));
}
}
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
// IS THIS NEEDED? --> // HttpContext.User = await _userClaimsPrincipalFactory.CreateAsync(user);
var tokens = _antiforgery.GetAndStoreTokens(HttpContext);
var identity = _jwtFactory.GenerateClaimsIdentity(model.Email, user.Id);
_logger.LogInformation(1, "User logged in.");
var jwt = await Tokens.GenerateJwt(identity, _jwtFactory, model.Email, _jwtOptions, new JsonSerializerSettings { Formatting = Formatting.Indented });
return new OkObjectResult(jwt);
}
if (result.RequiresTwoFactor)
{
//return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
}
if (result.IsLockedOut)
{
string message = "User account locked out.";
_logger.LogWarning(2, message);
return BadRequest(Errors.AddErrorToModelState("Email", message, ModelState));
}
if (result.IsNotAllowed)
{
string message = "User account is not allowed to sign in.";
_logger.LogWarning(2, message);
return BadRequest(Errors.AddErrorToModelState("Email", message, ModelState));
}
return BadRequest(Errors.AddErrorToModelState("", "Sign in failed.", ModelState));
}
return BadRequest(Errors.AddErrorToModelState("", "", ModelState));
}
public string GetUserId()
{
string username = string.Empty;
ClaimsPrincipal principal = HttpContext.User as ClaimsPrincipal;
if (HttpContext.User != null)
{
var id = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier);
if (id != null)
{
username = id.Value;
}
}
return username;
}
This is the code for GenerateJwt. (Are these fields standard? I see other fields being set in other code, such as in https://code-maze.com/authentication-aspnetcore-jwt-1/.)
public static async Task<string> GenerateJwt(ClaimsIdentity identity, IJwtFactory jwtFactory,string userName, JwtIssuerOptions jwtOptions, JsonSerializerSettings serializerSettings)
{
var response = new
{
id = identity.Claims.Single(c => c.Type == "id").Value,
auth_token = await jwtFactory.GenerateEncodedToken(userName, identity),
expires_in = (int)jwtOptions.ValidFor.TotalSeconds
}; // see GenerateEncodedToken pasted below.
return JsonConvert.SerializeObject(response, serializerSettings);
}
public async Task<string> GenerateEncodedToken(string userName, ClaimsIdentity identity)
{
var claims = new
{
new Claim(JwtRegisteredClaimNames.Sub, userName),
new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64),
identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Rol),
identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Id)
};
// Create the JWT security token and encode it.
var jwt = new JwtSecurityToken(
issuer: _jwtOptions.Issuer,
audience: _jwtOptions.Audience,
claims: claims,
notBefore: _jwtOptions.NotBefore,
expires: _jwtOptions.Expiration,
signingCredentials: _jwtOptions.SigningCredentials);
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
return encodedJwt;
}
These are the relevant lines in ConfigureServices.
// jwt wire up
// Get options from app settings
var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));
// Configure JwtIssuerOptions
services.Configure<JwtIssuerOptions>(options =>
{
options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)];
options.SigningCredentials = new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256);
});
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)],
ValidateAudience = true,
ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)],
ValidateIssuerSigningKey = true,
IssuerSigningKey = _signingKey,
RequireExpirationTime = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(configureOptions =>
{
configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
configureOptions.TokenValidationParameters = tokenValidationParameters;
configureOptions.SaveToken = true;
configureOptions.RequireHttpsMetadata = false;
});
// api user claim policy
services.AddAuthorization(options =>
{
options.AddPolicy("ApiUser", policy => policy.RequireClaim(Constants.Strings.JwtClaimIdentifiers.Rol, Constants.Strings.JwtClaims.ApiAccess));
});
// add identity
var builder = services.AddIdentity<AppUser, AppRole>(o =>
{
// configure identity options
o.Password.RequireDigit = false;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
o.Password.RequireNonAlphanumeric = false;
o.Password.RequiredLength = 6;
})
.AddSignInManager<SignInManager<AppUser>>()
.AddEntityFrameworkStores<AppIdentityDbContext>()
.AddDefaultTokenProviders();
I'm using the following to pass my token from Angular.
private authHeader(): HttpHeaders {
let headers = new HttpHeaders();
if (isPlatformBrowser(this.platformId)) {
headers = headers.set('Content-Type', 'application/json');
let authToken = this.windowRefService.nativeWindow.localStorage.getItem('auth_token');
headers = headers.set('Authorization', authToken);
headers = headers.set('X-XSRF-TOKEN', this.getCookie('XSRF-TOKEN'));
}
return headers;
}
protected jsonAuthRequestOptions = { headers: this.authHeader() };
public loggedInAs(): Observable<string> {
return this.http.post<any>(this.baseUrl + "api/Account/GetUserId", { } , this.jsonAuthRequestOptions)
.map(data => {
if (data) {
return data;
}
return '';
})
.catch(this.handleError);
}
Does JWT authentication automatically set HttpContext.User? Or do I have to do that explicitly?
My succeeding call fails. (User has no claims, though HttpContext.User is not null.) I don't know whether the problem is with relying on HttpContext.User, or whether there is something wrong with the token generation / consumption.
asp.net-core jwt
I have the following for my login code, and another method to retrieve the user ID in another call.
// POST: /api/Account/Login
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login([FromBody]LoginViewModel model)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByEmailAsync(model.Email);
if (user != null)
{
if (!await _userManager.IsEmailConfirmedAsync(user))
{
ModelState.AddModelError(string.Empty,
"You must have a confirmed email to log in.");
return BadRequest(Errors.AddErrorToModelState("Email", "You must have a confirmed email to log in.", ModelState));
}
}
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
// IS THIS NEEDED? --> // HttpContext.User = await _userClaimsPrincipalFactory.CreateAsync(user);
var tokens = _antiforgery.GetAndStoreTokens(HttpContext);
var identity = _jwtFactory.GenerateClaimsIdentity(model.Email, user.Id);
_logger.LogInformation(1, "User logged in.");
var jwt = await Tokens.GenerateJwt(identity, _jwtFactory, model.Email, _jwtOptions, new JsonSerializerSettings { Formatting = Formatting.Indented });
return new OkObjectResult(jwt);
}
if (result.RequiresTwoFactor)
{
//return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
}
if (result.IsLockedOut)
{
string message = "User account locked out.";
_logger.LogWarning(2, message);
return BadRequest(Errors.AddErrorToModelState("Email", message, ModelState));
}
if (result.IsNotAllowed)
{
string message = "User account is not allowed to sign in.";
_logger.LogWarning(2, message);
return BadRequest(Errors.AddErrorToModelState("Email", message, ModelState));
}
return BadRequest(Errors.AddErrorToModelState("", "Sign in failed.", ModelState));
}
return BadRequest(Errors.AddErrorToModelState("", "", ModelState));
}
public string GetUserId()
{
string username = string.Empty;
ClaimsPrincipal principal = HttpContext.User as ClaimsPrincipal;
if (HttpContext.User != null)
{
var id = HttpContext.User.FindFirst(ClaimTypes.NameIdentifier);
if (id != null)
{
username = id.Value;
}
}
return username;
}
This is the code for GenerateJwt. (Are these fields standard? I see other fields being set in other code, such as in https://code-maze.com/authentication-aspnetcore-jwt-1/.)
public static async Task<string> GenerateJwt(ClaimsIdentity identity, IJwtFactory jwtFactory,string userName, JwtIssuerOptions jwtOptions, JsonSerializerSettings serializerSettings)
{
var response = new
{
id = identity.Claims.Single(c => c.Type == "id").Value,
auth_token = await jwtFactory.GenerateEncodedToken(userName, identity),
expires_in = (int)jwtOptions.ValidFor.TotalSeconds
}; // see GenerateEncodedToken pasted below.
return JsonConvert.SerializeObject(response, serializerSettings);
}
public async Task<string> GenerateEncodedToken(string userName, ClaimsIdentity identity)
{
var claims = new
{
new Claim(JwtRegisteredClaimNames.Sub, userName),
new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(), ClaimValueTypes.Integer64),
identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Rol),
identity.FindFirst(Helpers.Constants.Strings.JwtClaimIdentifiers.Id)
};
// Create the JWT security token and encode it.
var jwt = new JwtSecurityToken(
issuer: _jwtOptions.Issuer,
audience: _jwtOptions.Audience,
claims: claims,
notBefore: _jwtOptions.NotBefore,
expires: _jwtOptions.Expiration,
signingCredentials: _jwtOptions.SigningCredentials);
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
return encodedJwt;
}
These are the relevant lines in ConfigureServices.
// jwt wire up
// Get options from app settings
var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));
// Configure JwtIssuerOptions
services.Configure<JwtIssuerOptions>(options =>
{
options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)];
options.SigningCredentials = new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256);
});
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)],
ValidateAudience = true,
ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)],
ValidateIssuerSigningKey = true,
IssuerSigningKey = _signingKey,
RequireExpirationTime = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(configureOptions =>
{
configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)];
configureOptions.TokenValidationParameters = tokenValidationParameters;
configureOptions.SaveToken = true;
configureOptions.RequireHttpsMetadata = false;
});
// api user claim policy
services.AddAuthorization(options =>
{
options.AddPolicy("ApiUser", policy => policy.RequireClaim(Constants.Strings.JwtClaimIdentifiers.Rol, Constants.Strings.JwtClaims.ApiAccess));
});
// add identity
var builder = services.AddIdentity<AppUser, AppRole>(o =>
{
// configure identity options
o.Password.RequireDigit = false;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
o.Password.RequireNonAlphanumeric = false;
o.Password.RequiredLength = 6;
})
.AddSignInManager<SignInManager<AppUser>>()
.AddEntityFrameworkStores<AppIdentityDbContext>()
.AddDefaultTokenProviders();
I'm using the following to pass my token from Angular.
private authHeader(): HttpHeaders {
let headers = new HttpHeaders();
if (isPlatformBrowser(this.platformId)) {
headers = headers.set('Content-Type', 'application/json');
let authToken = this.windowRefService.nativeWindow.localStorage.getItem('auth_token');
headers = headers.set('Authorization', authToken);
headers = headers.set('X-XSRF-TOKEN', this.getCookie('XSRF-TOKEN'));
}
return headers;
}
protected jsonAuthRequestOptions = { headers: this.authHeader() };
public loggedInAs(): Observable<string> {
return this.http.post<any>(this.baseUrl + "api/Account/GetUserId", { } , this.jsonAuthRequestOptions)
.map(data => {
if (data) {
return data;
}
return '';
})
.catch(this.handleError);
}
Does JWT authentication automatically set HttpContext.User? Or do I have to do that explicitly?
My succeeding call fails. (User has no claims, though HttpContext.User is not null.) I don't know whether the problem is with relying on HttpContext.User, or whether there is something wrong with the token generation / consumption.
asp.net-core jwt
asp.net-core jwt
edited 6 hours ago
asked yesterday
Jonas Arcangel
1,82443162
1,82443162
Are you callingservices.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(...
andapp.UseAuthentication();
inStartup.cs
?
– Albert
yesterday
Yes. services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(configureOptions => { configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)]; configureOptions.TokenValidationParameters = tokenValidationParameters; configureOptions.SaveToken = true; });
– Jonas Arcangel
yesterday
And did you set theapp.UseAuthentication()
onConfigure
method withinStartup.cs
file as well, before theUseMvc
? Double-check here
– Anderson Matos
yesterday
I also have app.UseAuthentication() as well as app.UseJwtTokenMiddleware() before UseMvc().
– Jonas Arcangel
yesterday
HttpContext.User exists, so I think it is getting authenticated. It's just that the Claims is empty.
– Jonas Arcangel
yesterday
|
show 1 more comment
Are you callingservices.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(...
andapp.UseAuthentication();
inStartup.cs
?
– Albert
yesterday
Yes. services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(configureOptions => { configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)]; configureOptions.TokenValidationParameters = tokenValidationParameters; configureOptions.SaveToken = true; });
– Jonas Arcangel
yesterday
And did you set theapp.UseAuthentication()
onConfigure
method withinStartup.cs
file as well, before theUseMvc
? Double-check here
– Anderson Matos
yesterday
I also have app.UseAuthentication() as well as app.UseJwtTokenMiddleware() before UseMvc().
– Jonas Arcangel
yesterday
HttpContext.User exists, so I think it is getting authenticated. It's just that the Claims is empty.
– Jonas Arcangel
yesterday
Are you calling
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(...
and app.UseAuthentication();
in Startup.cs
?– Albert
yesterday
Are you calling
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(...
and app.UseAuthentication();
in Startup.cs
?– Albert
yesterday
Yes. services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(configureOptions => { configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)]; configureOptions.TokenValidationParameters = tokenValidationParameters; configureOptions.SaveToken = true; });
– Jonas Arcangel
yesterday
Yes. services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(configureOptions => { configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)]; configureOptions.TokenValidationParameters = tokenValidationParameters; configureOptions.SaveToken = true; });
– Jonas Arcangel
yesterday
And did you set the
app.UseAuthentication()
on Configure
method within Startup.cs
file as well, before the UseMvc
? Double-check here– Anderson Matos
yesterday
And did you set the
app.UseAuthentication()
on Configure
method within Startup.cs
file as well, before the UseMvc
? Double-check here– Anderson Matos
yesterday
I also have app.UseAuthentication() as well as app.UseJwtTokenMiddleware() before UseMvc().
– Jonas Arcangel
yesterday
I also have app.UseAuthentication() as well as app.UseJwtTokenMiddleware() before UseMvc().
– Jonas Arcangel
yesterday
HttpContext.User exists, so I think it is getting authenticated. It's just that the Claims is empty.
– Jonas Arcangel
yesterday
HttpContext.User exists, so I think it is getting authenticated. It's just that the Claims is empty.
– Jonas Arcangel
yesterday
|
show 1 more comment
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53237854%2fasp-net-core-jwt-login-not-setting-httpcontext-user-claims%23new-answer', 'question_page');
}
);
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Are you calling
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(...
andapp.UseAuthentication();
inStartup.cs
?– Albert
yesterday
Yes. services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(configureOptions => { configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)]; configureOptions.TokenValidationParameters = tokenValidationParameters; configureOptions.SaveToken = true; });
– Jonas Arcangel
yesterday
And did you set the
app.UseAuthentication()
onConfigure
method withinStartup.cs
file as well, before theUseMvc
? Double-check here– Anderson Matos
yesterday
I also have app.UseAuthentication() as well as app.UseJwtTokenMiddleware() before UseMvc().
– Jonas Arcangel
yesterday
HttpContext.User exists, so I think it is getting authenticated. It's just that the Claims is empty.
– Jonas Arcangel
yesterday