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

点点圈 提交于 2019-12-08 05:41:58

问题


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


回答1:


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.




回答2:


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


来源:https://stackoverflow.com/questions/28734523/asp-identity-2-web-api-token-auth-persistent-claims-not-loading

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!