简体   繁体   中英

ASP Identity 2 + Web API Token Auth - Persistent claims not Loading

Im having some trouble with claims in ASP.NET Web API Token Auth.

Essentially I have created a user with some claims (values are being stored in the AspNetUserClaim table) but when the users identity is created, those claims are not being pulled from the database.

A breakdown of my setup is as follows.

  1. User Class: Has a GenerateUserIdentityAsync method (pretty standard) and a couple of custom properties:

     public class LibraryUser : IdentityUser{ //Add Custom Properties Here public string Company { get; set; } public string DisplayName { get; set; } public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<LibraryUser> manager, string authenticationType) { // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType var userIdentity = await manager.CreateIdentityAsync(this, authenticationType); // Add custom user claims here return userIdentity; } } 
  2. My DBContext declares some simple name changes to make the DB look nicer

     protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // Modify the Model creation properties.. modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); //Rename Identity 2.0 Tables to something nicer.. modelBuilder.Entity<LibraryUser>().ToTable("LibraryUser"); modelBuilder.Entity<IdentityUser>().ToTable("LibraryUser"); modelBuilder.Entity<IdentityRole>().ToTable("Role"); modelBuilder.Entity<IdentityUserRole>().ToTable("UserRole"); modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaim"); modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogin"); } 
  3. I have a Simple UserManager class called LibraryUserManager which just extends UserManager for my user Type.

     public class LibraryUserManager : UserManager<LibraryUser> 
  4. When the database is seeded (when calling Update-Database) the following user is created:

     // -- Create Admin User, put in admin role.. LibraryUserManager userManager = new LibraryUserManager(new UserStore<LibraryUser>(context)); var user = new LibraryUser() { UserName = "admin@admin.com", Email = "admin@admin.com", DisplayName = "Administrator", Company = "Test" }; userManager.Create(user, "Password1."); userManager.AddClaim(user.Id, new Claim(ClaimTypes.Role, "user")); userManager.AddClaim(user.Id, new Claim(ClaimTypes.Role, "author")); userManager.AddClaim(user.Id, new Claim(ClaimTypes.Role, "reviewer")); userManager.AddClaim(user.Id, new Claim(ClaimTypes.Role, "admin")); 
  5. Once this is run.. the database has the user (in the LibraryUser table) and the Claims (in the UserClaim table)

在此处输入图片说明

在此处输入图片说明

  1. When the user is being authenticated by my custom Auth Provider they are found (via the user manager) and the GenerateUserIdentityAsync is called:

EDIT : showing rest of that method...

    var userManager = context.OwinContext.GetUserManager<LibraryUserManager>();

    LibraryUser user = await userManager.FindAsync(context.UserName, context.Password);

    //check if a user exists
    if (user == null)
    {
        context.SetError("invalid_grant", "The user name or password is incorrect.");
        return;
    }

    ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, OAuthDefaults.AuthenticationType);
    AuthenticationProperties properties = CreateProperties(user.UserName, user.DisplayName, oAuthIdentity);           
    AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);

    context.Validated(ticket);
  1. Contents of create properties (called above):

     public static AuthenticationProperties CreateProperties(string userName, string displayName, ClaimsIdentity oAuthIdentity) { IDictionary<string, string> data = new Dictionary<string, string> { { "userName", userName }, { "displayName", displayName }, { "roles", string.Join(",", oAuthIdentity.Claims.Where(c => c.Type == ClaimTypes.Role).Select(c => c.Value).ToArray())} }; return new AuthenticationProperties(data); } 
  2. When the user is authed.. I have put a breakpoint in LibraryUser.GenerateUserIdentityAsync (code under point 1 above) and the only claims in the ClaimsIdentity.Claims collection returned by CreateIdentityAsync are the default ones (name, identity_provider, security_stamp and one other..) .. the claims I have manually added are not returned from the DB..

Can anyone see what I am missing??

I have tried to give all the info I can if you require more please comment and I will amend my question.

Thanks in advance :D

_L

There conflicting line is located inside the OnModelCreating method:

modelBuilder.Entity<LibraryUser>().ToTable("LibraryUser");
modelBuilder.Entity<IdentityUser>().ToTable("LibraryUser"); // <-- this one

Because you are using the LibraryUser as a derived class from IdentityUser, you don't need to explicitly map IdentityUser to a table. Doing it messes up with how the primary and foreign keys are generated in the database.

Claims to put in database(you did in AddClaim() ) and to make contain in token are different. You have to put claim data manually in inherited OAuthAuthorizationServerProvider class, which ASP.NET gives default ApplicatoinOAuthProvider.cs in Provider folder or whatever oauth provider you made.

At there, overriden GrantResourceOwnerCredentials() method did AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties); in order to put claims in token.

Then, Windows Identity will read the claims from token you put.

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        using (var userManager = _container.GetInstance<ApplicationUserManager>())
        {
            var user = await userManager.FindAsync(context.UserName, context.Password);
            if (user == null)
            {
                context.SetError("invalid_grant", "The user name or password is incorrect.");
                return;
            }

            ClaimsIdentity oAuthIdentity = await userManager.CreateIdentityAsync(user,
                context.Options.AuthenticationType);
            ClaimsIdentity cookiesIdentity = await userManager.CreateIdentityAsync(user,
                CookieAuthenticationDefaults.AuthenticationType);
            AuthenticationProperties properties = CreateProperties(user);

            // Below line adds additional claims in token.
            AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
            context.Validated(ticket);
            context.Request.Context.Authentication.SignIn(cookiesIdentity);
        }
    }


    public static AuthenticationProperties CreateProperties(AspNetUser user)
    {
        IDictionary<string, string> data = new Dictionary<string, string>
        {
            {"Id", user.Id.ToString(CultureInfo.InvariantCulture)},
            {"http://axschema.org/namePerson", user.Nickname,},
            {"http://axschema.org/contact/email", user.Email,},
        };

        return new AuthenticationProperties(data);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM