bbrinck
bbrinck

Reputation: 1103

.NET Core add Claim after AzuerAD Authentication

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

Answers (2)

LP13
LP13

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

Nan Yu
Nan Yu

Reputation: 27588

You can achieve that during the authentication , in OIDC middleware , OnTokenValidatedoffers 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

Related Questions