Microsoft.AspNet.Identity.EntityFramework.IdentityUser에서 ID 유형을 변경하는 방법
(ASP.NET MVC 5, EF6, VS2013)
유형에서 "Id"필드 의 유형 을 문자열에서 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);
...
}
따라서 userId가 문자열이어야하는 ASP.NET ID 프레임 워크에 구워진 다른 메서드가있는 것 같습니다. 이 클래스도 다시 구현해야합니까?
사용자 테이블의 ID에 대한 GUID를 저장하지 않는 이유에 대한 설명 :
-외래 키를 통해 데이터를 사용자 테이블에 연결하는 다른 테이블이 있습니다. (사용자가 사이트에 콘텐츠를 저장할 때) 더 큰 필드 유형을 사용하고 명확한 이점없이 추가 데이터베이스 공간을 사용할 이유가 없습니다. (GUID와 int ID 사용에 대한 다른 게시물이 있다는 것을 알고 있지만 많은 사람들이 int ID가 더 빠르고 공간을 적게 사용한다고 제안하는 것처럼 보이므로 여전히 궁금합니다.)
-사용자가 특정 사용자에 대한 데이터를 검색 할 수 있도록 편안한 엔드 포인트를 노출 할 계획입니다. 나는 생각한다 :
/users/123/name
보다 깨끗하다
/users/{af54c891-69ba-4ddf-8cb6-00d368e58d77}/name
ASP.NET 팀이 이러한 방식으로 ID를 구현하기로 결정한 이유를 아는 사람이 있습니까? 이것을 int 유형으로 변경하려고 시도하는 데 시력이 부족합니까? (아마 내가 놓친 혜택이있을 수 있습니다.)
감사...
-벤
따라서 int ID를 원하는 경우 고유 한 POCO IUser 클래스를 만들고 1.0 RTM 릴리스에서 사용자 지정 IUser 클래스에 대한 IUserStore를 구현해야합니다.
이것은 우리가 지원할 시간이 없었지만 지금은 1.1에서 이것을 쉽게 만드는 방법을 찾고 있습니다. 조만간 야간 빌드에서 무언가를 사용할 수 있기를 바랍니다.
1.1-alpha1 예제로 업데이트 됨 : 야간 빌드를 얻는 방법
최신 야간 비트로 업데이트하는 경우 지금 더 쉽게 만들 수있는 새로운 1.1-alpha1 API를 사용해 볼 수 있습니다. 예를 들어 문자열 대신 Guid를 연결하는 방법은 다음과 같습니다.
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);
}
}
사용 스테판 Cebulak 의 대답과 벤 포스터의 멋진 블로그 기사 베어 박탈 ASP.NET 신원 I 되세요 내가 ASP.NET 정체성에 적용한 다음 솔루션을 내놓았다 2.0 비주얼 스튜디오 2013에 의해 생성 된로 AccountController
.
이 솔루션은 정수를 사용자의 기본 키로 사용하고 데이터베이스로 이동하지 않고도 현재 로그인 한 사용자의 ID를 가져올 수 있습니다.
다음 단계를 따르십시오.
1. 사용자 지정 사용자 관련 클래스 만들기
기본적 으로는 기본 키 유형으로를 AccountController
사용하는 클래스를 사용 string
합니다. 대신를 사용하는 아래 클래스를 만들어야합니다 int
. 아래의 모든 클래스를 하나의 파일에 정의했습니다.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
}
}
사용자 정의를 작성합니다 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
사용자 정의 클래스를 사용하도록 수정
모든 변경 UserManager
을 AppUserManager
, UserStore
로 AppUserStore
등이 생성자의 예를 보자
public AccountController()
: this( new AppUserManager( new AppUserStore( new AppDbContext() ) ) )
{
}
public AccountController(AppUserManager userManager)
{
UserManager = userManager;
}
5. ClaimIdentity
쿠키 에 저장 하기 위해 사용자 ID를 클레임으로 추가
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);
}
만들기 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에 액세스 할 수 있습니다 . 이를 사용하여 사용자에게 속한 개체 만 쿼리 할 수 있습니다.
You don't have to take care of auto generation of user primary keys - no surprise, Entity Framework by default uses Identity for integer primary keys, when creating tables.
Warning! Keep in mind, that if you implement it in already released project, for already logged in users ClaimsType.Sid
will not exist and FindFirst
will return null in AppClaimsPrincipal
. You need to either force logout all users or handle this scenario in AppClaimsPrincipal
@HaoKung
I've succeeded to make int id's with your nightly builds. User.Identity.GetUserId() problem is still there, but i just did int.parse() for now.
The biggest suprise was that i did not need to create ID by myself, db was made with identity id and it was somehow automatically set for new users Oo...
Model:
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)
{
}
}
Controller:
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; }
Hope release build will come soon :D...
P.S. Can't write comments so i did an answer, sorry.
As stated here:
In Visual Studio 2013, the default web application uses a string value for the key for user accounts. ASP.NET Identity enables you to change the type of the key to meet your data requirements. For example, you can change the type of the key from a string to an integer.
This topic on the above link shows how to start with the default web application and change the user account key to an integer. You can use the same modifications to implement any type of key in your project. It shows how to make these changes in the default web application, but you could apply similar modifications to a customized application. It shows the changes needed when working with MVC or Web Forms.
Basically you have to :
-Change the type of the key to int in the Identity user class
-Add customized Identity classes that use int as key
-Change the context class and user manager to use int as key
-Change start-up configuration to use int as key
-Change the AccountController to pass int as key
here is link where all steps are explained to achieve this.
'developer tip' 카테고리의 다른 글
"authenticate_user!"의 구현은 어디에 있습니까? (0) | 2020.11.15 |
---|---|
부모 div 자동 크기를 자식 div의 너비로 만드는 방법 (0) | 2020.11.15 |
React.JS로 입력 값을 올바르게 검증하는 방법은 무엇입니까? (0) | 2020.11.15 |
Java에서 파일을 만들지 않고 경로가 유효한지 확인하는 방법이 있습니까? (0) | 2020.11.15 |
테이블 행의 마지막 셀이 나머지 모든 너비를 차지하도록 만드는 방법 (0) | 2020.11.15 |