添加列/属性到AspNetUserLogins /登录在IdentityDbContext [英] Add Columns/Properties to AspNetUserLogins/Logins in IdentityDbContext

查看:178
本文介绍了添加列/属性到AspNetUserLogins /登录在IdentityDbContext的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

可以向 AspNetUserLogins 表中添加列,或者将 IdentityUserLogin 类子类化,以使身份框架将正确使用该类?

Is it possible to add columns to the AspNetUserLogins table, or subclass the IdentityUserLogin class, such that the Identity Framework will use that class properly?

推荐答案

这是一个答案,但我确定不会最终成为最好的:

This is an answer but I'm sure it's not going to end up the best one:

可以做到这一点,但是它很丑陋。

It can be done, but it's ugly.

首先,你要做一个类您将要使用的所有仿制药,只是为了使您的生活更轻松。这些是:

First, you'll want to make a class of all the generics you're about to use, just to make your life easier. Those are:

[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 中找到。

(The above superclasses can be found in Microsoft.AspNet.Identity.EntityFramework).

将使以下通用定义更短,更难进入由于文书错误而无法编译的地方。

This is going to make the following generic definitions shorter, and harder to get into a place where they won't compile due to clerical errors.

当您在这里可能会很好地将它们添加到DbContext中,通常不会将它们提供给您:

While you're here may as well add these to the DbContext, which normally does not leave them available to you:

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>,

而且,访客将需要自己的调整匹配此声明:

And, Visitor is going to need its own adjustment to match this declaration:

public class Visitor : IdentityUser<string, LoginIdentity, StandardUserRole,
    IdentityUserClaim>

满足模型(最重要的是在自己的迁移项目中出现性能原因) 。但是,您仍然拥有所有需要处理的身份/ OWIN的东西。

That satisfies the Models (which btw, are best to have in their own Project for Migrations performance reasons). But, you've still got all the Identity/OWIN stuff to deal with.

默认情况下,您将获得涉及UserStore的ApplicationUserManager。它通常从UserManager继承,但现在将会太限制 - 您需要稍微扩展它:

By default you're provided with an ApplicationUserManager that involves a UserStore. It normally inherits from UserManager, but that's going to be too restrictive now - you need to slightly expand it:

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:

I warned you about crazy. 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);
    }
}

这应该让大部分的肮脏的工作。不容易。但是,做到这一点,你有一个工作实现,你可以添加额外的字段到登录表!您现在可以扩展OWIN Auth的东西来提供事件,并且可以听取创建新的登录。您可以通过添加额外的信息来响应这些信息。

That should get you through most of the dirty work. Not easy. But, having done that, you've got a working implementation where you can add extra fields to the Logins table! You can now extend the OWIN Auth stuff to provide events, and listen for the creation of new Logins. You can then respond to those by adding that extra info.

在我们的例子中,目标是从多个OpenId / OAuth提供商(Google,Facebook等)中拥有多个登录)跨多个电子邮件地址,单个用户/访问者帐户。框架确实支持这一点,但是,它并没有记录什么电子邮件与什么登录行相关联,这在将更多的登录与给定的帐户合并时非常重要。

In our case, the goal was to have multiple Logins from multiple OpenId/OAuth Providers (Google, Facebook, etc) across multiple email addresses, on a single User/Visitor account. The framework does support that, but, it doesn't make a record of what Email is associated with what Login row, which is important when merging more Logins with a given account.

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

还有更多的工作要做,但是从上述起点应该是比较明显的 - 除了一个例外,我将在这里指出。

There's more you'll need to do to get the whole thing working, but it should be relatively obvious from the above starting point - with one exception, which I'll point out here.

通过从 UserManager< TVisitor> UserManager< TVisitor,string> ,您悄悄地丢失了前者的内置ID代码功能。你需要自己效仿另外一方面,您最有可能将 Visitor 实现为 IUser< string> 。这样做将阻止您设置Id属性,因为它是只读(无设置器)。您可以通过第二个界面来避免这种情况:

By migrating from UserManager<TVisitor> to UserManager<TVisitor, string>, you quietly lose the ID-generation functionality built-in to the former. You'll need to emulate it yourself. As another gotcha, along the way you'll most likely implement Visitor as IUser<string>. Doing so will prevent you from setting the Id property, because it's read-only (no setter). You can avoid that with a second interface:

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(即使是抽象类):

With that in place you can set Id safely (even in an abstracted class):

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是必填字段。

Remember to do same for CreateAsync(Visitor user, string password). Otherwise created users explode with DbEntityValidationException complaining Id is a required field.

这篇关于添加列/属性到AspNetUserLogins /登录在IdentityDbContext的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆