ASP Identity 2 + Web API Token Auth - 持久声明未加载
ASP Identity 2 + Web API Token Auth - Persistent claims not Loading
我在 ASP.NET Web API 令牌验证中遇到了一些问题。
基本上我创建了一个具有一些声明的用户(值存储在 AspNetUserClaim table 中)但是当创建用户身份时,这些声明不会从数据库中提取。
我的设置细分如下。
User Class:有一个 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;
}
}
我的 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");
}
我有一个名为 LibraryUserManager 的简单 UserManager class,它只是为我的用户类型扩展了 UserManager。
public class LibraryUserManager : UserManager<LibraryUser>
为数据库播种(调用 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"));
一旦这是 运行.. 数据库就有用户(在 LibraryUser table 中)和声明(在 UserClaim table 中)
- 当用户通过我的自定义 Auth Provider 进行身份验证时(通过用户管理器)找到他们并调用 GenerateUserIdentityAsync:
编辑:显示该方法的其余部分...
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);
创建属性的内容(上面调用):
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);
}
当用户被授权时..我在 LibraryUser.GenerateUserIdentityAsync 中放置了一个断点(上面第 1 点下的代码)并且 CreateIdentityAsync 返回的 ClaimsIdentity.Claims 集合中的唯一声明是默认的(名称、identity_provider、security_stamp 和另一个..)..我手动添加的声明不会从数据库返回..
谁能看到我错过了什么??
我已尽力提供所有信息,如果您需要更多信息,请发表评论,我会修改我的问题。
提前致谢:D
_L
放入数据库的声明(您在 AddClaim()
中所做的)和包含在令牌中的声明是不同的。您必须手动将声明数据放入继承的 OAuthAuthorizationServerProvider
class,其中 ASP.NET 在 Provider 文件夹或您创建的任何 oauth 提供程序中提供默认值 ApplicatoinOAuthProvider.cs。
在那里,重写的 GrantResourceOwnerCredentials()
方法做了 AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
以便将声明放入令牌中。
然后,Windows身份将从您输入的令牌中读取声明。
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);
}
冲突行位于 OnModelCreating 方法中:
modelBuilder.Entity<LibraryUser>().ToTable("LibraryUser");
modelBuilder.Entity<IdentityUser>().ToTable("LibraryUser"); // <-- this one
因为您将 LibraryUser 用作从 IdentityUser 派生的 class,所以您不需要将 IdentityUser 显式映射到 table。这样做搞乱了数据库中主键和外键的生成方式。
我在 ASP.NET Web API 令牌验证中遇到了一些问题。
基本上我创建了一个具有一些声明的用户(值存储在 AspNetUserClaim table 中)但是当创建用户身份时,这些声明不会从数据库中提取。
我的设置细分如下。
User Class:有一个 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; } }
我的 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"); }
我有一个名为 LibraryUserManager 的简单 UserManager class,它只是为我的用户类型扩展了 UserManager。
public class LibraryUserManager : UserManager<LibraryUser>
为数据库播种(调用 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"));
一旦这是 运行.. 数据库就有用户(在 LibraryUser table 中)和声明(在 UserClaim table 中)
- 当用户通过我的自定义 Auth Provider 进行身份验证时(通过用户管理器)找到他们并调用 GenerateUserIdentityAsync:
编辑:显示该方法的其余部分...
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);
创建属性的内容(上面调用):
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); }
当用户被授权时..我在 LibraryUser.GenerateUserIdentityAsync 中放置了一个断点(上面第 1 点下的代码)并且 CreateIdentityAsync 返回的 ClaimsIdentity.Claims 集合中的唯一声明是默认的(名称、identity_provider、security_stamp 和另一个..)..我手动添加的声明不会从数据库返回..
谁能看到我错过了什么??
我已尽力提供所有信息,如果您需要更多信息,请发表评论,我会修改我的问题。
提前致谢:D
_L
放入数据库的声明(您在 AddClaim()
中所做的)和包含在令牌中的声明是不同的。您必须手动将声明数据放入继承的 OAuthAuthorizationServerProvider
class,其中 ASP.NET 在 Provider 文件夹或您创建的任何 oauth 提供程序中提供默认值 ApplicatoinOAuthProvider.cs。
在那里,重写的 GrantResourceOwnerCredentials()
方法做了 AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
以便将声明放入令牌中。
然后,Windows身份将从您输入的令牌中读取声明。
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);
}
冲突行位于 OnModelCreating 方法中:
modelBuilder.Entity<LibraryUser>().ToTable("LibraryUser");
modelBuilder.Entity<IdentityUser>().ToTable("LibraryUser"); // <-- this one
因为您将 LibraryUser 用作从 IdentityUser 派生的 class,所以您不需要将 IdentityUser 显式映射到 table。这样做搞乱了数据库中主键和外键的生成方式。