为什么ASP.NET标识接口使用字符串作为主键和外键?

为什么ASP.NET标识接口使用字符串作为主键和外键?,asp.net,asp.net-identity,Asp.net,Asp.net Identity,我首先查看新ASP.NET标识类上的接口以及它使用实体框架代码创建的数据库。我正在使用Visual Studio 2013 RC 乍一看,数据库架构看起来相当正常: 但是所有的键都是NVARCHAR(128) 出于某种疯狂的原因,AspNetUserSecrets.Id是一个PK,看起来它可以指向AspNetUsers表中的多个记录。这是否意味着多个aspnetuser必须共享同一密码 当我看到你被迫实现的接口时,这些都是字符串 public class User : IUser {

我首先查看新ASP.NET标识类上的接口以及它使用实体框架代码创建的数据库。我正在使用Visual Studio 2013 RC

乍一看,数据库架构看起来相当正常:

但是所有的键都是NVARCHAR(128)

出于某种疯狂的原因,
AspNetUserSecrets.Id
是一个PK,看起来它可以指向
AspNetUsers
表中的多个记录。这是否意味着多个
aspnetuser
必须共享同一密码

当我看到你被迫实现的接口时,这些都是字符串

public class User : IUser
{
    public string Id { get; set; }
    public string UserName { get; set; }
}

public class UserSecret : IUserSecret
{
    public string UserName { get; set; }
    public string Secret { get; set; }
}

public class UserRole : IUserRole
{
    public string UserId { get; set; }
    public string RoleId { get; set; }
}

public class UserClaim : IUserClaim
{
    public string UserId { get; set; }
    public string ClaimType { get; set; }
    public string ClaimValue { get; set; }
}

public class UserManagement : IUserManagement
{
    public string UserId { get; set; }
    public bool DisableSignIn { get; set; }
    public DateTime LastSignInTimeUtc { get; set; }
}

public class Tokens : IToken
{
    public string Id { get; set; }
    public string Value { get; set; }
    public DateTime ValidUntilUtc { get; set; }
}

public class UserLogin : IUserLogin
{
    public string UserId { get; set; }
    public string LoginProvider { get; set; }
    public string ProviderKey { get; set; }
}

public class Role : IRole
{
    public string Id { get; set; }
    public string Name { get; set; }
}
因此,我开始接受这样一个事实:我可能必须使用PK和FK关系的字符串来实现这一点

但我真的很想知道为什么它是这样建造的…?

编辑:时间已经过去,现在有关于如何扩展asp.net标识以使用int(或guid)字段的文章:


目的是允许两种任意id类型(即
int
guid
字符串
),但也避免id属性出现序列化/强制转换问题

因此,您可以随意定义密钥,只需实现接口方法即可

public class MyUser : IUser {
  public int Id { get; set; }
  string IUser.Id { get { return Id.ToString(); } }
}

此外,郝说:

  • Identity runtime更喜欢用户ID的字符串,因为我们不想搞清楚用户ID的正确序列化(出于同样的原因,我们使用字符串进行声明),例如,所有(或大多数)标识接口都将用户ID称为字符串
  • 自定义持久性层(例如实体类型)的人可以选择他们想要的键的任何类型,但他们自己也可以为我们提供键的字符串表示
  • 默认情况下,我们为每个新用户使用guid的字符串表示,但这只是因为它为我们自动生成唯一id提供了一种非常简单的方法

  • 使用ASP.NET Core,您可以用一种非常简单的方法为Identity的模型指定所需的数据类型

    第一步,将标识类从重写为

    公共类应用程序用户:IdentityUser
    {
    }
    公共类应用程序角色:IdentityRole
    {
    }
    
    使用类和所需的数据类型声明数据库上下文:

    public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, Guid>
        {
            public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
                : base(options)
            {
            }
    
            protected override void OnModelCreating(ModelBuilder builder)
            {
                base.OnModelCreating(builder);
                // Customize the ASP.NET Identity model and override the defaults if needed.
                // For example, you can rename the ASP.NET Identity table names and more.
                // Add your customizations after calling base.OnModelCreating(builder);
            }
        }
    
    public类ApplicationDbContext:IdentityDbContext
    {
    公共应用程序DBContext(DbContextOptions选项)
    :基本(选项)
    {
    }
    模型创建时受保护的覆盖无效(ModelBuilder)
    {
    基于模型创建(生成器);
    //自定义ASP.NET标识模型,并根据需要覆盖默认值。
    //例如,可以重命名ASP.NET标识表名称等。
    //在调用base.OnModelCreating(builder)后添加自定义项;
    }
    }
    
    在startup类中,使用模型声明identity service,并声明主键所需的数据类型:

    services.AddIdentity<ApplicationUser, ApplicationRole>()
                .AddEntityFrameworkStores<ApplicationDbContext, Guid>()
                .AddDefaultTokenProviders();
    
    services.AddIdentity()
    .AddEntityFrameworkStores()
    .AddDefaultTokenProviders();
    
    在ASP.NET标识表中,主键仍将位于NVARCHAR中,但在应用程序中,主键将是所需的数据类型。 您可以在控制器中对此进行检查:

        [HttpGet]
        public async Task<IActionResult> Test()
        {
            ApplicationUser user = await _userManager.GetUserAsync(HttpContext.User);
            Guid userId = user.Id; // No cast from string, it's a Guid data type
            throw new NotImplementedException();
        }
    
    [HttpGet]
    公共异步任务测试()
    {
    ApplicationUser=await\u userManager.GetUserAsync(HttpContext.user);
    Guid userId=user.Id;//不从字符串强制转换,它是Guid数据类型
    抛出新的NotImplementedException();
    }
    
    您正在使用测试版。最终版本与我的理解不同。我听说他们已经完全删除了AspNetUserSecrets表。这将解决其中一个问题:)但我仍然不明白为什么所有的密钥都是NVARCHER(128)…很抱歉,因为答案是由内部人员提供的,我早就应该将其标记为正确的。为什么如果这是将id用作int所需的唯一代码,我们有这样的
    InEnumerable
    :到处都是?从Identity的角度来看,这就是所有需要的,将会有一系列相应的应用程序代码更改。总的来说,这是相当令人难以接受的,我们已经在Identity V3中尝试过简化这一点。我想要简单的生活,但CodePlex没有Identity 3.0的路线图。因此,你能给我们一个大概的日期吗?如果您在显式接口声明中得到“'IUser.Id'不是接口的成员”,那么将上述代码更改为:
    string IUser.Id{get{return Id.ToString();}}
    c#也可以根据返回类型实现不同的方法签名。由于这是一个限制,microsoft不能创建Identity.EntityFramework.Int包、GuiD包和所有选项吗?@Rick为什么是nvarchar(128)而不是uniqueidentifier?官方文档中有一篇文章回答了这个问题:如果我不想定义角色,我们将通过ACL处理角色。
        [HttpGet]
        public async Task<IActionResult> Test()
        {
            ApplicationUser user = await _userManager.GetUserAsync(HttpContext.User);
            Guid userId = user.Id; // No cast from string, it's a Guid data type
            throw new NotImplementedException();
        }