是否可以将列添加到AspNetUserLogins表中,或者将IdentityUserLogin类划分为子类,以便Identity Framework正确使用该类?
发布于 2017-08-09 04:34:54
这是一个答案,但我相信它不会是最好的:
这是可以做到的,但它很丑陋。
首先,您需要将您将要使用的所有泛型划分为一个类,这只是为了让您的工作更轻松。它们是:
[Table("AspNetUserRoles")]
public class StandardUserRole : IdentityUserRole<string>
[Table("AspNetRoles")]
public class StandardRole : IdentityRole<string, StandardUserRole>
[Table("AspNetUserLogins")]
public class LoginIdentity : IdentityUserLogin(上面的超类可以在Microsoft.AspNet.Identity.EntityFramework中找到)。
这将使下面的泛型定义变得更短,并且更难进入由于文书错误而无法编译的地方。
当你在这里的时候,也可以将它们添加到DbContext中,这通常不会让你可以使用它们:
public DbSet<LoginIdentity> LoginIdentities { get; set; }
public DbSet<StandardUserRole> UserRoles { get; set; }现在,疯狂的事情来了:
public class Db :
// Replace this with a custom implementation
//IdentityDbContext<Visitor>,
IdentityDbContext<Visitor, StandardRole, string, LoginIdentity,
StandardUserRole, IdentityUserClaim>,而且,Visitor将需要自己的调整来匹配此声明:
public class Visitor : IdentityUser<string, LoginIdentity, StandardUserRole,
IdentityUserClaim>这满足了模型(顺便说一句,出于迁移性能的原因,最好在他们自己的项目中拥有这些模型)。但是,你仍然需要处理所有的身份/拥有的东西。
默认情况下,会为您提供一个包含UserStore的ApplicationUserManager。它通常继承自UserManager,但现在限制太多了-你需要稍微扩展它:
public class VisitorManager : UserManager<Visitor, string>
{
public VisitorManager(IUserStore<Visitor, string> store)
: base(store)
{
}
public static VisitorManager Create(
IdentityFactoryOptions<VisitorManager> options,
IOwinContext context)
{
var manager = new VisitorManager(new UserStore<Visitor,
StandardRole, string, LoginIdentity, StandardUserRole,
IdentityUserClaim>(context.Get<Db>()));我警告过你不要发疯。SignInManager:
public class SignInManager : SignInManager<Visitor, string>
{
public SignInManager(VisitorManager userManager,
IAuthenticationManager authenticationManager)
: base(userManager, authenticationManager)
{
}
public override Task<ClaimsIdentity> CreateUserIdentityAsync(
Visitor user)
{
return user.GenerateUserIdentityAsync((VisitorManager)UserManager);
}
public static SignInManager Create(
IdentityFactoryOptions<SignInManager> options, IOwinContext context)
{
return new SignInManager(context.GetUserManager<VisitorManager>(),
context.Authentication);
}
}这应该能帮你完成大部分的苦差事。这可不容易。但是,这样做之后,您就有了一个可以工作的实现,您可以向Logins表中添加额外的字段!您现在可以扩展OWIN Auth内容来提供事件,并监听新登录的创建。然后,您可以通过添加额外的信息来响应这些信息。
在我们的例子中,我们的目标是让多个OpenId/OAuth提供商(Google、Facebook等)在一个用户/访问者帐户上跨多个电子邮件地址进行多次登录。该框架确实支持这一点,但它不会记录哪些电子邮件与哪些登录行相关联,这在与给定帐户合并更多登录时非常重要。
[Table("AspNetUserLogins")]
public class LoginIdentity : IdentityUserLogin
{
/// <summary>
/// The email address associated with this identity at this provider
/// </summary>
[MaxLength(300)]
public string Email { get; set; }
}您还需要做更多的工作才能让整个工作正常,但从上面的起点来看,这应该是相对明显的-除了一个例外,我将在这里指出。
通过从UserManager<TVisitor>迁移到UserManager<TVisitor, string>,您会悄悄地失去前者内置的ID生成功能。你需要自己去模拟它。另一个问题是,在此过程中,您很可能会将Visitor实现为IUser<string>。这样做将阻止您设置Id属性,因为它是只读的(没有setter)。您可以使用第二个接口来避免这种情况:
public interface IVisitor
{
string Id { get; set; }
string Uid { get; set; }
string UserName { get; set; }
string Email { get; set; }
string FirstName { get; set; }
string LastName { get; set; }
ICollection<StandardUserRole> Roles { get; }
ICollection<LoginIdentity> Logins { get; }
}有了这些,您就可以安全地设置Id了(即使在抽象类中也是如此):
public override Task<IdentityResult> CreateAsync(Visitor user)
{
var guid = Guid.NewGuid();
string id = guid.ToString();
((IVisitor)user).Id = id;
return base.CreateAsync(user);
}请记住对CreateAsync(访问者用户,字符串密码)执行相同的操作。否则创建的用户使用DbEntityValidationException分解,抱怨Id是必填字段。
https://stackoverflow.com/questions/45558065
复制相似问题