Asp.net-Mvc

如何更改 Microsoft.AspNet.Identity.EntityFramework.IdentityUse…

  • October 23, 2013

(ASP.NET MVC 5、EF6、VS2013)

我試圖弄清楚如何將類型中的“Id”欄位的類型從字元串更改為 int

Microsoft.AspNet.Identity.EntityFramework.IdentityUser

為了讓新使用者帳戶與整數 ID 而不是 GUID 相關聯。但這似乎比在我的派生使用者類中簡單地添加一個 int 類型的新 Id 屬性更複雜。看看這個方法簽名:

(來自大會 Microsoft.AspNet.Identity.Core.dll)

public class UserManager<TUser> : IDisposable where TUser : global::Microsoft.AspNet.Identity.IUser
 {
 ...
 public virtual Task<IdentityResult> AddLoginAsync(string userId, UserLoginInfo login);
 ...
 }

因此,ASP.NET 身份框架中似乎還有其他方法要求 userId 是一個字元串。我還需要重新實現這些類嗎?

關於為什麼我不想在使用者表中儲存 id 的 GUID 的解釋:

  • 將有其他表通過外鍵將數據與使用者表相關聯。(當使用者在網站上保存內容時。)我認為沒有理由使用更大的欄位類型並花費額外的數據庫空間而沒有明顯的優勢。(我知道還有其他關於使用 GUID 與 int id 的文章,但似乎很多人建議 int id 更快並且使用更少的空間,這仍然讓我想知道。)

-我計劃公開一個 restful 端點以允許使用者檢索有關特定使用者的數據。我想:

/users/123/name

比干淨

/users/{af54c891-69ba-4ddf-8cb6-00d368e58d77}/name

有誰知道為什麼 ASP.NET 團隊決定以這種方式實現 ID?我在嘗試將其更改為 int 類型時是否短視?(也許我缺少一些好處。)

謝謝…

-Ben

因此,如果您想要 int id,您需要創建自己的 POCO IUser 類並在 1.0 RTM 版本中為您的自定義 IUser 類實現您的 IUserStore。

這是我們沒有時間支持的東西,但我現在正在考慮在 1.1 中使這更容易(ier)。希望很快會在夜間建構中提供一些東西。

更新了 1.1-alpha1 範例: 如何獲取夜間建構

如果您更新到最新的夜間位,您可以嘗試新的 1.1-alpha1 api,這應該會使這現在更容易:例如,插入 Guids 而不是字元串應該是這樣的

   public class GuidRole : IdentityRole<Guid, GuidUserRole> { 
       public GuidRole() {
           Id = Guid.NewGuid();
       }
       public GuidRole(string name) : this() { Name = name; }
   }
   public class GuidUserRole : IdentityUserRole<Guid> { }
   public class GuidUserClaim : IdentityUserClaim<Guid> { }
   public class GuidUserLogin : IdentityUserLogin<Guid> { }

   public class GuidUser : IdentityUser<Guid, GuidUserLogin, GuidUserRole, GuidUserClaim> {
       public GuidUser() {
           Id = Guid.NewGuid();
       }
       public GuidUser(string name) : this() { UserName = name; }
   }

   private class GuidUserContext : IdentityDbContext<GuidUser, GuidRole, Guid, GuidUserLogin, GuidUserRole, GuidUserClaim> { }
   private class GuidUserStore : UserStore<GuidUser, GuidRole, Guid, GuidUserLogin, GuidUserRole, GuidUserClaim> {
       public GuidUserStore(DbContext context)
           : base(context) {
       }
   }
   private class GuidRoleStore : RoleStore<GuidRole, Guid, GuidUserRole> {
       public GuidRoleStore(DbContext context)
           : base(context) {
       }
   }

   [TestMethod]
   public async Task CustomUserGuidKeyTest() {
       var manager = new UserManager<GuidUser, Guid>(new GuidUserStore(new GuidUserContext()));
       GuidUser[] users = {
           new GuidUser() { UserName = "test" },
           new GuidUser() { UserName = "test1" }, 
           new GuidUser() { UserName = "test2" },
           new GuidUser() { UserName = "test3" }
           };
       foreach (var user in users) {
           UnitTestHelper.IsSuccess(await manager.CreateAsync(user));
       }
       foreach (var user in users) {
           var u = await manager.FindByIdAsync(user.Id);
           Assert.IsNotNull(u);
           Assert.AreEqual(u.UserName, user.UserName);
       }
   }

使用Stefan Cebulak的回答和 Ben Foster 的精彩部落格文章ASP.NET Identity Stripped Bare我想出了以下解決方案,我已將其應用於 ASP.NET Identity 2.0並由 Visual Studio 2013 生成AccountController

該解決方案使用整數作為使用者的主鍵,還允許在不訪問數據庫的情況下獲取目前登錄使用者的 ID。

以下是您需要遵循的步驟:

1.創建自定義使用者相關類

預設情況下,AccountController使用的類string作為主鍵類型。我們需要創建下面的類,它將使用 anint來代替。我在一個文件中定義了以下所有類:AppUser.cs

public class AppUser :
   IdentityUser<int, AppUserLogin, AppUserRole, AppUserClaim>,
   IUser<int>
{

}

public class AppUserLogin : IdentityUserLogin<int> { }

public class AppUserRole : IdentityUserRole<int> { }

public class AppUserClaim : IdentityUserClaim<int> { }

public class AppRole : IdentityRole<int, AppUserRole> { }

擁有一個自定義的 ClaimsPrincipal 也很有用,它可以很容易地暴露使用者的 ID

public class AppClaimsPrincipal : ClaimsPrincipal
{
   public AppClaimsPrincipal( ClaimsPrincipal principal ) : base( principal )
   { }

   public int UserId
   {
       get { return int.Parse(this.FindFirst( ClaimTypes.Sid ).Value); }
   }
}

2.創建自定義IdentityDbContext

我們應用程序的數據庫上下文將擴展IdentityDbContext,預設情況下實現所有與身份驗證相關的 DbSet。即使DbContext.OnModelCreating是一個空方法,我也不確定IdentityDbContext.OnModelCreating,所以在覆蓋時,記得呼叫base.OnModelCreating( modelBuilder ) AppDbContext.cs

public class AppDbContext :
   IdentityDbContext<AppUser, AppRole, int, AppUserLogin, AppUserRole, AppUserClaim>
{
   public AppDbContext() : base("DefaultConnection")
   {
       // Here use initializer of your choice
       Database.SetInitializer( new CreateDatabaseIfNotExists<AppDbContext>() );
   }


   // Here you define your own DbSet's



   protected override void OnModelCreating( DbModelBuilder modelBuilder )
   {
       base.OnModelCreating( modelBuilder );

       // Here you can put FluentAPI code or add configuration map's
   }
}
  1. 創建自定義UserStoreand UserManager,將在上面使用

AppUserStore.cs

public interface IAppUserStore : IUserStore<AppUser, int>
{

}

public class AppUserStore :
   UserStore<AppUser, AppRole, int, AppUserLogin, AppUserRole, AppUserClaim>,
   IAppUserStore
{
   public AppUserStore() : base( new AppDbContext() )
   {

   }

   public AppUserStore(AppDbContext context) : base(context)
   {

   }
}

AppUserManager.cs

public class AppUserManager : UserManager<AppUser, int>
{
   public AppUserManager( IAppUserStore store ) : base( store )
   {

   }
}

4.修改AccountController以使用您的自定義類

將所有更改UserManagerAppUserManager,等。以這個建構子為例:UserStore``AppUserStore

public AccountController()
   : this( new AppUserManager( new AppUserStore( new AppDbContext() ) ) )
{
}

public AccountController(AppUserManager userManager)
{
   UserManager = userManager;
}
  1. 添加使用者 ID 作為ClaimIdentity儲存在 cookie 中的聲明

在第 1 步中,我們創建了AppClaimsPrincipal,它公開了從 中取出的 UserId ClaimType.Sid。但是,要使此聲明可用,我們需要在使用者登錄時添加它。在AccountController一個SingInAsync方法中負責登錄。我們需要在這個方法中添加一行,來添加聲明。

private async Task SignInAsync(AppUser user, bool isPersistent)
{
   AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
   ClaimsIdentity identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);

   // Extend identity claims
   identity.AddClaim( new Claim( ClaimTypes.Sid, user.Id.ToString() ) );

   AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}

BaseController6.用CurrentUser屬性創建一個

要在您的控制器中輕鬆訪問目前登錄的使用者 ID,請創建一個 abstract BaseController,您的控制器將從中派生。在 中BaseController,創建CurrentUser如下:

public abstract class BaseController : Controller
{
   public AppClaimsPrincipal CurrentUser
   {
       get { return new AppClaimsPrincipal( ( ClaimsPrincipal )this.User ); }
   }


   public BaseController()
   {

   }
}

7.繼承你的控制器BaseController並享受

從現在開始,您可以CurrentUser.UserId在控制器中使用來訪問目前登錄使用者的 ID,而無需訪問數據庫。您可以使用它來僅查詢屬於使用者的對象。

您不必關心使用者主鍵的自動生成 - 毫不奇怪,Entity Framework 在創建表時預設使用 Identity 作為整數主鍵。

**警告!**請記住,如果您在已經發布的項目中實現它,對於已經登錄的使用者ClaimsType.Sid將不存在並且FindFirst將在AppClaimsPrincipal. 您需要強制註銷所有使用者或在AppClaimsPrincipal

引用自:https://stackoverflow.com/questions/19553424