Reputation: 1103
My application signs in via AzureAD, but now I need to get information from the DB and then store the Role as a Claim.
So my question is: How can I store the Role as Claim after authentication ?
This is what I tried:
var user = User as ClaimsPrincipal;
var identity = user.Identity as ClaimsIdentity;
identity.AddClaim(new Claim(ClaimTypes.Role, "Admin"));
But when I go to another controller, the claim does not exist anymore ?
Thanks
Upvotes: 4
Views: 3269
Reputation: 34149
In OnTokenValidated
event, you can throw specific exception when user does not exists your database. and then OnRemoteFailure
event redirect user to specific action method for that particular exception
options.Events = new OpenIdConnectEvents()
{
OnTokenValidated = async context =>
{
// get email claim
var emailClaim = context.Principal.Claims.SingleOrDefault(x => x.Type == ClaimTypes.Email);
UserEntity cu = null;
using (var accountService = context.HttpContext.RequestServices.GetService<IAccountService>())
{
cu = await accountService.Authorize(emailClaim.Value);
}
if (cu == null)
{
throw new UnauthorizedAccessException(string.Format("Could not find user for login '{0}' ", emailClaim.Value));
}
var newIdentity = new ClaimsIdentity(context.Principal.Identity.AuthenticationType);
// keep the id_token for logout
newIdentity.AddClaim(new Claim("id_token", context.ProtocolMessage.IdToken));
// add email claim
newIdentity.AddClaim(emailClaim);
// add email value as name claim
newIdentity.AddClaim(new Claim(ClaimTypes.Name, emailClaim.Value));
// add other claims here like roles
context.Properties.IsPersistent = true;
context.Properties.ExpiresUtc = DateTime.UtcNow.AddHours(3);
// overwrite existing authentication ticket
context.Principal = new ClaimsPrincipal(newIdentity);
},
OnRedirectToIdentityProviderForSignOut = async context =>
{
var idTokenHint = context.HttpContext?.User?.FindFirst("id_token");
if (idTokenHint != null)
context.ProtocolMessage.IdTokenHint = idTokenHint.Value;
await Task.FromResult(0);
},
OnRemoteFailure = async context =>
{
if (context.Failure is UnauthorizedAccessException)
{
context.Response.Redirect("/Account/UnAuthorized");
}
else
{
context.Response.Redirect("/Account/Error");
}
context.HandleResponse();
await Task.FromResult(0);
}
};
AccontController.cs
public class AccountController : Controller
{
[AllowAnonymous]
public IActionResult UnAuthorized()
{
HttpContext.Session.Clear();
await Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions.SignOutAsync(HttpContext, CookieAuthenticationDefaults.AuthenticationScheme);
await Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions.SignOutAsync(HttpContext, OpenIdConnectDefaults.AuthenticationScheme);
}
}
Upvotes: 0
Reputation: 27588
You can achieve that during the authentication , in OIDC middleware , OnTokenValidated
offers you the chance to modify the ClaimsIdentity obtained from the incoming token , code below is for your reference :
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Events = new OpenIdConnectEvents
{
OnTokenValidated = ctx =>
{
//query the database to get the role
// add claims
var claims = new List<Claim>
{
new Claim(ClaimTypes.Role, "Admin")
};
var appIdentity = new ClaimsIdentity(claims);
ctx.Principal.AddIdentity(appIdentity);
return Task.CompletedTask;
},
};
});
Then in controller , you can get the claim like :
var role = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Role)?.Value;
Upvotes: 7