How to add custom claims on user identity .net 6

M.H. Mukit 26 Reputation points
2022-09-15T19:21:12.87+00:00

When logging in, I was looking for a way to add more user claims. I discovered the following implementation on the.net 6 using IUserClaimsPrincipalFactory. However, this has the drawback of calling the database with each HTTP request. So instead of calling the database with every http request, I simply wanted to do so once (during initial authentication).

https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.iclaimstransformation?view=aspnetcore-6.0

I found the following implmentation for .net 5.
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/add-user-data?view=aspnetcore-5.0&tabs=visual-studio#add-claims-to-identity-using-iuserclaimsprincipalfactoryapplicationuser

Please explain to me why the IUserClaimsPrincipalFactory is not listed in the.net 6 documentation. What are the drawbacks, and is there another option than utilizing/not utilizing IClaimsTransformation to call the database once during authentication not for each HTTP call?

ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,080 questions
{count} votes

3 answers

Sort by: Most helpful
  1. SurferOnWww 1,796 Reputation points
    2022-09-24T01:30:44.377+00:00

    However, this has the drawback of calling the database with each HTTP request. So instead of calling the database with every http request, I simply wanted to do so once (during initial authentication).

    You can do so by using the IUserClaimsPrincipalFactory.

    For example, how to add the Phone number to ClaimsIdentity is described below.

    244442-account.jpg

    (1) Add the following class as the service:

    using Microsoft.AspNetCore.Identity;  
    using Microsoft.Extensions.Options;  
    using MvcCore6App2.Data;  
    using System.Security.Claims;  
      
    namespace MvcCore6App2.Services  
    {  
        public class CustomClaimsPrincipalFactory :  
            UserClaimsPrincipalFactory<ApplicationUser>  
        {  
            public CustomClaimsPrincipalFactory(  
                UserManager<ApplicationUser> userManager,  
                IOptions<IdentityOptions> optionsAccessor)  
                    : base(userManager, optionsAccessor)  
            {  
            }  
      
            // This method is called only when login. It means that "the drawback   
            // of calling the database with each HTTP request" never happen.  
            public async override Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)  
            {  
                var principal = await base.CreateAsync(user);  
                  
                if (!string.IsNullOrEmpty(user.PhoneNumber))  
                {  
                    if (principal.Identity != null)  
                    {  
                        ((ClaimsIdentity)principal.Identity).AddClaims(  
                            new[] {  new Claim("Phone", user.PhoneNumber) });  
                    }  
                }  
      
                return principal;  
            }  
        }  
    }  
    

    (2) Register the above service in the Program.cs as follows:

    builder.Services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>,   
        CustomClaimsPrincipalFactory>();  
      
    

    (3) Result after login:

    244426-debug.jpg

    1 person found this answer helpful.
    0 comments No comments

  2. Qing Guo - MSFT 881 Reputation points Microsoft Vendor
    2022-09-23T09:11:47.663+00:00

    Hi @M.H. Mukit ,

    So instead of calling the database with every http request, I simply wanted to do so once (during initial authentication).

    Try to add claims in an ASP.NET Core middleware after Authentication.

    Middleware:

     public class SomeMiddleware  
        {  
            private readonly RequestDelegate _next;  
      
            public SomeMiddleware(RequestDelegate next)  
            {  
                _next = next;  
            }  
      
            public async Task InvokeAsync(HttpContext httpContext)  
            {  
                if (httpContext.User != null && httpContext.User.Identity.IsAuthenticated)  
                {  
                    var claims = new List<Claim>  
                {  
                    new Claim("SomeClaim", "SomeValue")  
                };  
      
                    var appIdentity = new ClaimsIdentity(claims);  
                    httpContext.User.AddIdentity(appIdentity);  
                }  
      
                await _next(httpContext);  
            }  
    

    Program:

      app.UseAuthentication();  
         app.UseAuthorization();  
         app.UseMiddleware<SomeMiddleware>();  
    

    ----------

    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,
    Qing Guo


  3. Bruce (SqlWork.com) 53,501 Reputation points
    2022-09-23T17:05:17.087+00:00

    which identity provider are you using?

    1) if custom provider, you add the claim to the entity database and map:

    https://learn.microsoft.com/en-us/aspnet/core/security/authentication/customize-identity-model?view=aspnetcore-6.0

    2) if using oauth, then use the OnTokenValidated event to add the claim. it will get copied to the cookie.

    https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.jwtbearer.jwtbearerevents.ontokenvalidated?view=aspnetcore-6.0

    note: if you are using azure ad access tokens, they will need to added on every request. I use a cache instead of a database.

    0 comments No comments