Search code examples
asp.net-coreasp.net-core-identity

Core 3.0 ApplicationUser is always empty


I have extended Identityuser

public class ApplicationUser : IdentityUser
{
    [MaxLength(150)]
    public string FirstName { get ; set ; }

    [MaxLength(150)] 
    public string LastName { get ; set ; }

    public int AlternateUserId { get ; set ; }

    [MaxLength(150)] 
    public string CompanyName { get ; set ; }

    [MaxLength(38)] 
    [Required] 
    public string ClientId { get ; set ; }

    [Required] 
    public int ShortClient { set ; get ; }

    public bool  Locked { set ; get ; }
}

In Startup.cs i have:

 services.AddIdentity<ApplicationUser, IdentityRole>().AddDefaultUI().AddEntityFrameworkStores<ApplicationDbContext>();
 services.AddSingleton<ApplicationUser>();

But in

public static class IdentityExtentionMethods
{
   public static string FirstName(this IIdentity identity)
   {
      var claim = ((ClaimsIdentity)identity).FindFirst(ClaimTypes.GivenName);

      // Test for null to avoid issues during local testing
      return (claim != null) ? claim.Value : string.Empty;
   }
}

Claim is always null and anywhere I try to inject ApplicationUser the variable is available but it is not populated with the user information.

@inject ApplicationUser applicationUser
@inject SignInManager<ApplicationUser> signInManager;

Instead it has some dummy values in a few of the Guid fields and most everything else is null.


Solution

  • As Chris Pratt points out you can't get ApplicationUser via injection in Core 3.x I am not sure about earlier versions. To bad its not in the documentation anywhere that I could see.

    But you can get

    SignInManager<ApplicationUser> _signInManager, 
    UserManager <ApplicationUser> _userManager
    ApplicationDbContext  _dbContext
    

    And as Chris also points out you can get

    ClaimsPrincipal

    and

    IPrincipal

    I have IPrincipal and as the code shows below, that with SignInManager & UserManager is all you need to get ApplicationUser

    public static class IdentityExtentionMethods
    {
        public static bool IsSysAdmin(this IPrincipal _principal,
                                 SignInManager<ApplicationUser> _signInManager, 
                                 UserManager <ApplicationUser> _userManager)
        {              
             var x = isSysAdmin(_principal, _signInManager, _userManager);
             if (x.Result == false)
                 return false;
             else
                 return true;
         }
    
         public static async Task<bool> isSysAdmin(this IPrincipal _principal,
                                SignInManager<ApplicationUser> _signInManager,
                                 UserManager <ApplicationUser> _userManager)
         {
             var ci = _principal.Identity as ClaimsIdentity;
             var userName = ci != null ? ci.FindFirst(ClaimTypes.Name) : null;
             string username = userName?.Value;
                // get ApplicationUser
             var appUser = await _userManager.FindByNameAsync( username);
             var _userClaims = await   
                     _signInManager.ClaimsFactory.CreateAsync(appUser);
             if (_userClaims.UserHasThisPermission(Permissions.AccessAll))
                 return true;
             else
                 return false;
    
         }
         public static bool HasRole( this IPrincipal _principal,                                                           
                                     string roleName,
                                     SignInManager<ApplicationUser> _signInManager, 
                                     UserManager <ApplicationUser> _userManager,
                                       ApplicationDbContext _dbContext)
    
        {
            var x = hasrole ( _principal , roleName , _signInManager , _userManager , _dbContext ) ;
            if (x.Result == false)
                return false;
            else
                return true;
        }
        private static async Task<bool> hasrole ( this IPrincipal _principal,
                                     string roleName,
                                      SignInManager<ApplicationUser> _signInManager, 
                                      UserManager <ApplicationUser> _userManager,
                                      ApplicationDbContext _dbContext)
        { 
             if (roleName == null) 
                 throw new ArgumentNullException(nameof(roleName));
    
             var ci = _principal.Identity as ClaimsIdentity;
             var userName = ci != null ? ci.FindFirst(ClaimTypes.Name) : null;
             string username = userName?.Value;
             var appUser = await _userManager.FindByNameAsync( username);
    
             if (_dbContext.Find<UserToRole>(appUser.Id, roleName) != null)
             {
                 return true ;
             }
    
             return false ;
        }
    }
    

    You access like this from _layout.cshtml

    @using Microsoft.AspNetCore.Identity        
    @inject ApplicationDbContext dbcontext ;
    @inject UserManager<ApplicationUser> userManager ;
    @inject SignInManager<ApplicationUser> signInManager;
    
    ;;
    ;;
    
    @if ( this.User.IsSysAdmin ( signInManager , userManager ) )
    {
       <!-- add menu stuff -->
    }
    @if ( this.User.HasRole ( signInManager , userManager,dbcontext ) )
    {
       <!-- add menu stuff -->
    }
    

    certainly seems like a lot of stuff to pass around but it gets the job done.

    BTW, the claims stuff is from https://www.thereformedprogrammer.net/part-7-adding-the-better-asp-net-core-authorization-code-into-your-app/

    Jon Smith has written a wonderful app which has an MIT open source license and allows you to use roles and permissions in Core 3.0/1 It is very complex but he provided a scaled down version https://github.com/JonPSmith/PermissionsOnlyApp that works well. Thanks Jon.