web-dev-qa-db-ja.com

Microsoft.AspNet.Identity.EntityFramework.IdentityUserでIDのタイプを変更する方法

(ASP.NET MVC 5、EF6、VS2013)

「Id」フィールドのタイプをstringからintに変更するの方法を見つけようとしています。

Microsoft.AspNet.Identity.EntityFramework.IdentityUser

新しいユーザーアカウントをGUIDではなく整数IDに関連付けるため。しかし、これは単純に、派生ユーザークラスに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 IDフレームワークに焼き付けられた他のメソッドがあり、userIdを文字列にする必要があるようです。これらのクラスも再実装する必要がありますか?

IDのGUIDをユーザーテーブルに保存したくない理由の説明:

-外部キーを介してユーザーテーブルにデータを関連付ける他のテーブルがあります。 (ユーザーがサイトにコンテンツを保存するとき。)より大きなフィールドタイプを使用し、明確な利点のない余分なデータベーススペースを使用する理由はありません。 (GUIDとint idの使用に関する他の投稿があることは知っていますが、int idの方が高速でスペースが少ないことを多くの人が示唆しているようです。

-ユーザーが特定のユーザーに関するデータを取得できるように、安らかなエンドポイントを公開する予定です。おもう:

/users/123/name

よりきれいです

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

ASP.NETチームがこの方法でIDを実装することにした理由は誰にもわかりますか?これをint型に変更しようとすると、近視眼的ですか? (おそらく私が見逃している利点があります。)

ありがとう...

-ベン

66
BenjiFB

したがって、int idが必要な場合は、独自のPOCO IUserクラスを作成し、1.0 RTMリリースでカスタムIUserクラスのIUserStoreを実装する必要があります。

これはサポートする時間がありませんでしたが、現時点では1.1でこれを簡単にすることを検討しています。うまくいけば、すぐにナイトリービルドで何かが利用できるようになります。

1.1-alpha1の例で更新:ナイトリービルドの入手方法

毎晩最新のビットに更新する場合は、新しい1.1-alpha1 APIを試してみてください。これにより、これがより簡単になります。

    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);
        }
    }
30
Hao Kung

Stefan Cebulak の回答とBen Fosterの素晴らしいブログ記事を使用 ASP.NET Identity Stripped Bare ASP.NETに適用した以下のソリューションを思い付きましたID2.0とVisual Studio 2013 AccountControllerによって生成されます。

このソリューションでは、整数をユーザーの主キーとして使用し、データベースにアクセスせずに現在ログインしているユーザーのIDを取得することもできます。

手順は次のとおりです。従う必要があります。

1.ユーザー関連のカスタムクラスを作成する

デフォルトでは、AccountControllerは、stringを使用しているクラスを主キーのタイプとして使用します。代わりにintを使用する以下のクラスを作成する必要があります。 1つのファイルで以下のすべてのクラスを定義しました: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> { }

また、ユーザーのIDを簡単に公開するカスタムClaimsPrincipalがあると便利です。

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

3.上記を使用するカスタムUserStoreおよび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に、UserStoreAppUserStoreなどに変更します。このコンストラクターの例を挙げます。

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

public AccountController(AppUserManager userManager)
{
    UserManager = userManager;
}

5. Cookieに保存されているClaimIdentityへのクレームとしてユーザーのIDを追加します

ステップ1では、ClaimType.Sidから取得したUserIdを公開するAppClaimsPrincipalを作成しました。ただし、この要求を使用可能にするには、ユーザーのログイン時に要求を追加する必要があります。 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);
}

6. BaseControllerプロパティでCurrentUserを作成します

コントローラーで現在ログインしているユーザーのIDに簡単にアクセスできるようにするには、抽象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は存在せず、FindFirstAppClaimsPrincipalにnullを返します。すべてのユーザーを強制的にログアウトするか、AppClaimsPrincipalでこのシナリオを処理する必要があります。

52
krzychu

しゅう

あなたのナイトリービルドでint idを作ることに成功しました。 User.Identity.GetUserId()の問題はまだありますが、とりあえずint.parse()をしました。

最大の驚きは、自分でIDを作成する必要がなかったことです。dbはID idで作成され、新しいユーザー向けに自動的に設定されました。

型:

    public class ApplicationUser : IdentityUser<int, IntUserLogin, IntUserRole, IntUserClaim>
{
    public ApplicationUser()
    {
    }
    public ApplicationUser(string name) : this() { UserName = name; }
}

public class ApplicationDbContext : IntUserContext
{
    public ApplicationDbContext()
    {

    }
}

private class IntRole : IdentityRole<int, IntUserRole>
{
    public IntRole()
    {
    }
    public IntRole(string name) : this() { Name = name; }
}
private class IntUserRole : IdentityUserRole<int> { }
private class IntUserClaim : IdentityUserClaim<int> { }
private class IntUserLogin : IdentityUserLogin<int> { }
private class IntUserContext : IdentityDbContext<ApplicationUser, IntRole, int, IntUserLogin, IntUserRole, IntUserClaim>
{
    public IntUserContext()
        : base("DefaultConnection")
    {

    }
}
private class IntUserStore : UserStore<ApplicationUser, IntRole, int, IntUserLogin, IntUserRole, IntUserClaim>
{
    public IntUserStore(DbContext context)
        : base(context)
    {

    }
}
private class IntRoleStore : RoleStore<IntRole, int, IntUserRole>
{
    public IntRoleStore(DbContext context)
        : base(context)
    {
    }
}

コントローラ:

        public AccountController()
        : this(new UserManager<ApplicationUser, int>(new IntUserStore(new ApplicationDbContext())))
    {
    }

    public AccountController(UserManager<ApplicationUser, int> userManager)
    {
        UserManager = userManager;
    }

    public UserManager<ApplicationUser, int> UserManager { get; private set; }

リリースビルドがすぐに来ることを願っています:D ...

追伸コメントを書くことができないので、回答しました、ごめんなさい。

6
Stefan Cebulak

述べたように ここ

Visual Studio 2013では、デフォルトのWebアプリケーションはユーザーアカウントのキーに文字列値を使用します。 ASP.NET Identityを使用すると、データ要件に合わせてキーのタイプを変更できます。たとえば、キーのタイプを文字列から整数に変更できます。

上記のリンクのこのトピックでは、デフォルトのWebアプリケーションから開始し、ユーザーアカウントキーを整数に変更する方法を示します。同じ変更を使用して、プロジェクトに任意のタイプのキーを実装できます。デフォルトのWebアプリケーションでこれらの変更を行う方法を示していますが、カスタマイズされたアプリケーションに同様の変更を適用することもできます。 MVCまたはWebフォームで作業するときに必要な変更を示しています。

4
Manik Arora

基本的にあなたがする必要があります:

-Identityユーザークラスでキーのタイプをintに変更する
-intをキーとして使用するカスタマイズされたIdentityクラスを追加します
-コンテキストクラスとユーザーマネージャーを変更して、intをキーとして使用する
-起動設定を変更して、intをキーとして使用する
-AccountControllerを変更して、intをキーとして渡す

here は、これを達成するためのすべての手順が説明されているリンクです。

3
lyz