ASP身份2 + Web API令牌身份验证 - 持久声明未加载

时间:2015-02-26 04:32:12

标签: c# authentication asp.net-web-api asp.net-identity asp.net-identity-2

我在ASP.NET Web API Token Auth中遇到了一些问题。

基本上我创建了一个具有一些声明的用户(值存储在AspNetUserClaim表中)但是当创建用户身份时,这些声明不会从数据库中提取。

我的设置细分如下。

  1. 用户类:具有GenerateUserIdentityAsync方法(非常标准)和一些自定义属性:

    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. 我的DBContext声明了一些简单的名称更改,以使数据库看起来更好

    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. 我有一个名为LibraryUserManager的简单UserManager类,它只为我的用户类型扩展UserManager。

    public class LibraryUserManager : UserManager<LibraryUser>
    
  4. 当数据库被播种时(调用Update-Database时),将创建以下用户:

    // -- 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. 运行后..数据库有用户(在LibraryUser表中)和Claims(在UserClaim表中)

  6. enter image description here

    enter image description here

    1. 当我的自定义Auth Provider对用户进行身份验证时,会找到它们(通过用户管理器)并调用GenerateUserIdentityAsync:
    2. 编辑:显示该方法的其余部分......

          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. 创建属性的内容(在上面调用):

        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. 当用户被authed时..我在LibraryUser.GenerateUserIdentityAsync(上面第1点下的代码)中放置了一个断点,并且CreateIdentityAsync返回的ClaimsIdentity.Claims集合中的唯一声明是默认声明(name,identity_provider) ,security_stamp和另外一个..)..我手动添加的声明不会从数据库返回..

      3. 任何人都能看到我错过的东西吗?

        如果您需要更多请注释我试图提供所有信息,我会修改我的问题。

        提前致谢:D

        _L

2 个答案:

答案 0 :(得分:2)

有冲突的行位于OnModelCreating方法内:

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

由于您使用LibraryUser作为IdentityUser的派生类,因此您无需将IdentityUser显式映射到表。这样做会弄乱数据库中如何生成主键和外键。

答案 1 :(得分:0)

声称放入数据库(您在AddClaim()中执行的操作)并使其包含在令牌中是不同的。您必须手动将声明数据放在继承的OAuthAuthorizationServerProvider类中,ASP.NET在Provider文件夹或您提供的任何oauth提供程序中提供默认的ApplicatoinOAuthProvider.c。

在那里,覆盖GrantResourceOwnerCredentials()方法AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);,以便将声明置于令牌中。

然后,Windows Identity将读取您放置的令牌的声明。

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