Reputation: 1274
I have created identityserver4 project and tried to add more claims after user log in. Here is my code
public async Task<IActionResult> Login(LoginInputModel model)
{
if (ModelState.IsValid)
{
// validate username/password against in-memory store
CoreDb.Models.User user = null;
if (( user = await _userService.VerifyUser(model.Username, model.Password)) != null)
{
// var user = _users.FindByUsername(model.Username);
await _events.RaiseAsync(new UserLoginSuccessEvent(user.Name, user.Id.ToString(), user.Name));
// only set explicit expiration here if user chooses "remember me".
// otherwise we rely upon expiration configured in cookie middleware.
var props = new AuthenticationProperties();
if (AccountOptions.AllowRememberLogin && model.RememberLogin)
{
props.IsPersistent = true;
props.ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration);
};
props.Items.Add("scheme", AccountOptions.WindowsAuthenticationSchemeName);
// issue authentication cookie with subject ID and username
await HttpContext.SignInAsync(user.Id.ToString(), user.Name, "idp", props, _userService.GetUserClaims(user).ToArray());
//IEnumerable<ClaimsIdentity> claimsIdentity = null;
//var claimsIdentity = new ClaimsIdentity(_userService.GetUserClaims(user), CookieAuthenticationDefaults.AuthenticationScheme);
//await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity));
// make sure the returnUrl is still valid, and if so redirect back to authorize endpoint or a local page
if (_interaction.IsValidReturnUrl(model.ReturnUrl) || Url.IsLocalUrl(model.ReturnUrl))
{
return Redirect(model.ReturnUrl);
}
return Redirect("~/");
}
await _events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials"));
ModelState.AddModelError("", AccountOptions.InvalidCredentialsErrorMessage);
}
However, I do not see my claims for the user when I call my api in requirement handler although my user id is there. What is an appropriate way to add user claims?
Upvotes: 1
Views: 3012
Reputation: 218
As Jay already mentioned, you can write your own ProfileService. If you don't use aspnetidentity you can just add the Claims in the Login method and add these lines to the GetProfileDataAsync Method of your ProfileService:
List<Claim> claims = context.Subject.Claims.Where(x => x.Type == JwtClaimTypes.Role).ToList();
context.IssuedClaims.AddRange(claims);
Upvotes: 1
Reputation: 1889
The claims must be added to the response context. If you are using aspnetidentity then the following approach will work for you
Ensure to include ProfileService implementation and hook up to IdentityServer at ConfigureServices
.AddProfileService<ProfileService>();
private readonly IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory;
In the GetProfileDataAsync, you can include your new claims
/// <summary>
/// This method is called whenever claims about the user are requested (e.g. during token creation or via the userinfo endpoint)
/// </summary>
/// <param name="context">The context.</param>
/// <returns></returns>
public override async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var sub = context.Subject.GetSubjectId();
var user = await userManager.FindByIdAsync(sub);
var principal = await claimsFactory.CreateAsync(user);
//context.AddFilteredClaims(principal.Claims);
context.IssuedClaims.AddRange(principal.Claims);
context.IssuedClaims.Add(new Claim("IP Address", coreOperations.GetCurrentRequestIPAddress()));
}
Upvotes: 2