.NET Core 在 AzuerAD 身份验证后添加声明

.NET Core add Claim after AzuerAD Authentication

我的应用程序通过 AzureAD 登录,但现在我需要从数据库中获取信息,然后将角色存储为声明。

所以我的问题是:如何在身份验证后将角色存储为声明?

这是我试过的:

var user = User as ClaimsPrincipal;
var identity = user.Identity as ClaimsIdentity;
identity.AddClaim(new Claim(ClaimTypes.Role, "Admin"));  

但是当我转到另一个控制器时,声明不再存在了?

谢谢

你可以在认证的时候实现,在OIDC中间件中,OnTokenValidated给你机会修改传入的token中获取的ClaimsIdentity,下面的代码供你参考:

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;
        },
    };
});

然后在 controller 中,你可以得到这样的声明:

var role = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Role)?.Value;

OnTokenValidated事件中,当用户不存在你的数据库时,你可以抛出特定的异常。然后 OnRemoteFailure 事件将用户重定向到该特定异常的特定操作方法

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);
        }
   }