.net Core Identity w/o EntityFramework 使用 int id
.net Core Identity w/o EntityFramework using int ids
我正在尝试使用 Identity w/o EntityFramework 创建一个 .net Core 解决方案,但使用整数 ID(UserId 和 RoleId)。我已按照此基本设置创建解决方案并删除 EF (https://taherchhabra.github.io/jekyll/update/2016/09/22/aspnet-core-identity-without-entityframework.html),但这仍然有用户的愚蠢 Guid id 列。当我尝试更改它时,我 运行 在创建 UserStore
时遇到了问题,因为它继承自 IUserStore<User>
,这需要我实现
Task<User> FindByIdAsync(string userId, CancellationToken cancellationToken)
which or course 表示 Id 值是字符串而不是 int。
我读过几篇关于如何更改基于 EF 的解决方案以使用整数的文章,我深入研究了 EF 是如何做到这一点的,但它都是基于使用 TKey
的 EF 类 .
我尝试创建自己的 IUserStore 以将字符串更改为整数,但该项目甚至无法启动(它可以正常编译但是当我尝试 运行 它在本地它会在完成启动之前退出向上)。
有谁知道如何做到这一点?我搜索了很多,但找不到任何东西。
编辑:
到目前为止我所做的是创建我自己的 UserStore 和 RollStore(它们基本上只是原件的副本,一旦我开始工作我将对其进行调整)。在我的 HomeController 中,我添加了以下内容:
public class HomeController : Controller
{
private readonly UserManager<models.User> _userManager;
public HomeController(UserManager<models.User> userManager)
{
_userManager = userManager;
}
public async Task<IActionResult> Index()
{
var user = new models.User();
if(User.Identity.IsAuthenticated)
user = await _userManager.FindByNameAsync(User.Identity.Name);
return View();
}
}
这基本上是一个 "is it plugged in" 测试,我可以在调试器中单步执行。
在我的 Startup.cs
:
services.AddSingleton<IUserStore<User>, UserStore>();
services.AddSingleton<IRoleStore<Role>, RoleStore>();
services.AddIdentity<User, Role>()
.AddDefaultTokenProviders();
这确实有效(通过我的端点进行调试,user
已正确填充)。但是,如果仔细观察,我会意识到 IUserStore
和 IRoleStore
是 Microsoft.AspNetCore.Identity
版本,这意味着我仍然依赖于这些合同并且需要使用 Guid 作为 Id。
如果我强制这个问题,使用
services.AddSingleton<SandboxCoreDapper.Identity.Interfaces.IUserStore<User>, UserStore>();
services.AddSingleton<SandboxCoreDapper.Identity.Interfaces.IRoleStore<Role>, RoleStore>();
然后当我尝试访问我的端点时,UserManager 将无法解析:
"Unable to resolve service for type 'Microsoft.AspNetCore.Identity.IUserStore1[SandboxCoreDapper.Models.User]' while attempting to activate 'Microsoft.AspNetCore.Identity.UserManager
1[SandboxCoreDapper.Models.User]'."
编辑 2
我发现这个有趣的讨论:https://github.com/aspnet/Identity/issues/493
在此基础上,我继续创建了自己的 RoleManager
和 UserManager
,它们基本上只是扩展了 Identity 版本:
namespace SandboxCoreDapper.Identity.Services
{
public class UserManager<TUser> : Microsoft.AspNetCore.Identity.UserManager<TUser> where TUser : class
{
public UserManager(
sandyId.IUserStore<TUser> store, // my version of IUserStore
IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<TUser> passwordHasher,
IEnumerable<IUserValidator<TUser>> userValidators,
IEnumerable<IPasswordValidator<TUser>> passwordValidators,
ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors,
IServiceProvider services,
ILogger<UserManager<TUser>> logger)
:base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
{
}
}
}
RoleManager
.
也是如此
然后我添加到Startup.cs
services.AddIdentity<User, Role>()
.AddDefaultTokenProviders()
.AddUserManager<SandboxCoreDapper.Identity.Services.UserManager<User>>()
.AddRoleManager<SandboxCoreDapper.Identity.Services.RoleManager<Role>>()
;
目前一切顺利...
这是对我的评论的回应,你的 question/comment:
只需声明您自己的 UserStore,然后将其注册到 Startup.cs。
这是我为适应这种情况而实现的 UserStore:
public class UserStore : IUserPasswordStore<Login>, IUserEmailStore<Login>, IUserPhoneNumberStore<Login>
{
private readonly IAccountRepo _accountRepo;
public UserStore(IAccountRepo accountRepo)
{
_accountRepo = accountRepo;
}
public void Dispose()
{
}
public async Task<string> GetUserIdAsync(Login user, CancellationToken cancellationToken)
{
return await Task.FromResult(user.Username);
}
public async Task<string> GetUserNameAsync(Login user, CancellationToken cancellationToken)
{
return await Task.FromResult(user.Username);
}
public Task SetUserNameAsync(Login user, string userName, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<string> GetNormalizedUserNameAsync(Login user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public async Task SetNormalizedUserNameAsync(Login user, string normalizedName, CancellationToken cancellationToken)
{
await Task.FromResult(user.Username = normalizedName.ToLower());
}
public async Task<IdentityResult> CreateAsync(Login user, CancellationToken cancellationToken)
{
await _accountRepo.CreateLogin(user);
return IdentityResult.Success;
}
public async Task<IdentityResult> UpdateAsync(Login user, CancellationToken cancellationToken)
{
await _accountRepo.UpdateLogin(user.LoginId, user.Email, true);
return IdentityResult.Success;
}
public Task<IdentityResult> DeleteAsync(Login user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public async Task<Login> FindByIdAsync(string userId, CancellationToken cancellationToken)
{
return await _accountRepo.GetUser(userId);
}
public async Task<Login> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)
{
return await _accountRepo.GetUser(normalizedUserName);
}
public async Task SetPasswordHashAsync(Login user, string passwordHash, CancellationToken cancellationToken)
{
if (user.LoginId != 0)
{
await _accountRepo.ChangePassword(user.Email, user.Username, passwordHash);
}
user.PasswordHash = passwordHash;
}
public async Task<string> GetPasswordHashAsync(Login user, CancellationToken cancellationToken)
{
return await Task.FromResult(user.PasswordHash);
}
public async Task<bool> HasPasswordAsync(Login user, CancellationToken cancellationToken)
{
return await Task.FromResult(!string.IsNullOrEmpty(user.PasswordHash) && !string.IsNullOrEmpty(user.Salt));
}
public Task SetEmailAsync(Login user, string email, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<string> GetEmailAsync(Login user, CancellationToken cancellationToken)
{
return Task.FromResult(user.Email);
}
public async Task<bool> GetEmailConfirmedAsync(Login user, CancellationToken cancellationToken)
{
return await Task.FromResult(user.EmailConfirmed);
}
public Task SetEmailConfirmedAsync(Login user, bool confirmed, CancellationToken cancellationToken)
{
return Task.FromResult(user.EmailConfirmed = confirmed);
}
public Task<Login> FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<string> GetNormalizedEmailAsync(Login user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task SetNormalizedEmailAsync(Login user, string normalizedEmail, CancellationToken cancellationToken)
{
return Task.FromResult(user.Email = normalizedEmail.ToLower());
}
public Task SetPhoneNumberAsync(Login user, string phoneNumber, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<string> GetPhoneNumberAsync(Login user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<bool> GetPhoneNumberConfirmedAsync(Login user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task SetPhoneNumberConfirmedAsync(Login user, bool confirmed, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
以及 Startup.cs ConfigureServices 方法:
services.AddSingleton<IUserStore<Login>, UserStore>();
我最接近的答案是这个 git 项目:https://github.com/grandchamp/Identity.Dapper
它仍在进行中,我正在与项目所有者合作进行一些改进,但对于遇到这个问题的其他人来说,现在该项目是你最好的选择。
我正在尝试使用 Identity w/o EntityFramework 创建一个 .net Core 解决方案,但使用整数 ID(UserId 和 RoleId)。我已按照此基本设置创建解决方案并删除 EF (https://taherchhabra.github.io/jekyll/update/2016/09/22/aspnet-core-identity-without-entityframework.html),但这仍然有用户的愚蠢 Guid id 列。当我尝试更改它时,我 运行 在创建 UserStore
时遇到了问题,因为它继承自 IUserStore<User>
,这需要我实现
Task<User> FindByIdAsync(string userId, CancellationToken cancellationToken)
which or course 表示 Id 值是字符串而不是 int。
我读过几篇关于如何更改基于 EF 的解决方案以使用整数的文章,我深入研究了 EF 是如何做到这一点的,但它都是基于使用 TKey
的 EF 类 .
我尝试创建自己的 IUserStore 以将字符串更改为整数,但该项目甚至无法启动(它可以正常编译但是当我尝试 运行 它在本地它会在完成启动之前退出向上)。
有谁知道如何做到这一点?我搜索了很多,但找不到任何东西。
编辑: 到目前为止我所做的是创建我自己的 UserStore 和 RollStore(它们基本上只是原件的副本,一旦我开始工作我将对其进行调整)。在我的 HomeController 中,我添加了以下内容:
public class HomeController : Controller
{
private readonly UserManager<models.User> _userManager;
public HomeController(UserManager<models.User> userManager)
{
_userManager = userManager;
}
public async Task<IActionResult> Index()
{
var user = new models.User();
if(User.Identity.IsAuthenticated)
user = await _userManager.FindByNameAsync(User.Identity.Name);
return View();
}
}
这基本上是一个 "is it plugged in" 测试,我可以在调试器中单步执行。
在我的 Startup.cs
:
services.AddSingleton<IUserStore<User>, UserStore>();
services.AddSingleton<IRoleStore<Role>, RoleStore>();
services.AddIdentity<User, Role>()
.AddDefaultTokenProviders();
这确实有效(通过我的端点进行调试,user
已正确填充)。但是,如果仔细观察,我会意识到 IUserStore
和 IRoleStore
是 Microsoft.AspNetCore.Identity
版本,这意味着我仍然依赖于这些合同并且需要使用 Guid 作为 Id。
如果我强制这个问题,使用
services.AddSingleton<SandboxCoreDapper.Identity.Interfaces.IUserStore<User>, UserStore>();
services.AddSingleton<SandboxCoreDapper.Identity.Interfaces.IRoleStore<Role>, RoleStore>();
然后当我尝试访问我的端点时,UserManager 将无法解析:
"Unable to resolve service for type 'Microsoft.AspNetCore.Identity.IUserStore1[SandboxCoreDapper.Models.User]' while attempting to activate 'Microsoft.AspNetCore.Identity.UserManager
1[SandboxCoreDapper.Models.User]'."
编辑 2 我发现这个有趣的讨论:https://github.com/aspnet/Identity/issues/493
在此基础上,我继续创建了自己的 RoleManager
和 UserManager
,它们基本上只是扩展了 Identity 版本:
namespace SandboxCoreDapper.Identity.Services
{
public class UserManager<TUser> : Microsoft.AspNetCore.Identity.UserManager<TUser> where TUser : class
{
public UserManager(
sandyId.IUserStore<TUser> store, // my version of IUserStore
IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<TUser> passwordHasher,
IEnumerable<IUserValidator<TUser>> userValidators,
IEnumerable<IPasswordValidator<TUser>> passwordValidators,
ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors,
IServiceProvider services,
ILogger<UserManager<TUser>> logger)
:base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger)
{
}
}
}
RoleManager
.
然后我添加到Startup.cs
services.AddIdentity<User, Role>()
.AddDefaultTokenProviders()
.AddUserManager<SandboxCoreDapper.Identity.Services.UserManager<User>>()
.AddRoleManager<SandboxCoreDapper.Identity.Services.RoleManager<Role>>()
;
目前一切顺利...
这是对我的评论的回应,你的 question/comment:
只需声明您自己的 UserStore,然后将其注册到 Startup.cs。
这是我为适应这种情况而实现的 UserStore:
public class UserStore : IUserPasswordStore<Login>, IUserEmailStore<Login>, IUserPhoneNumberStore<Login>
{
private readonly IAccountRepo _accountRepo;
public UserStore(IAccountRepo accountRepo)
{
_accountRepo = accountRepo;
}
public void Dispose()
{
}
public async Task<string> GetUserIdAsync(Login user, CancellationToken cancellationToken)
{
return await Task.FromResult(user.Username);
}
public async Task<string> GetUserNameAsync(Login user, CancellationToken cancellationToken)
{
return await Task.FromResult(user.Username);
}
public Task SetUserNameAsync(Login user, string userName, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<string> GetNormalizedUserNameAsync(Login user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public async Task SetNormalizedUserNameAsync(Login user, string normalizedName, CancellationToken cancellationToken)
{
await Task.FromResult(user.Username = normalizedName.ToLower());
}
public async Task<IdentityResult> CreateAsync(Login user, CancellationToken cancellationToken)
{
await _accountRepo.CreateLogin(user);
return IdentityResult.Success;
}
public async Task<IdentityResult> UpdateAsync(Login user, CancellationToken cancellationToken)
{
await _accountRepo.UpdateLogin(user.LoginId, user.Email, true);
return IdentityResult.Success;
}
public Task<IdentityResult> DeleteAsync(Login user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public async Task<Login> FindByIdAsync(string userId, CancellationToken cancellationToken)
{
return await _accountRepo.GetUser(userId);
}
public async Task<Login> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)
{
return await _accountRepo.GetUser(normalizedUserName);
}
public async Task SetPasswordHashAsync(Login user, string passwordHash, CancellationToken cancellationToken)
{
if (user.LoginId != 0)
{
await _accountRepo.ChangePassword(user.Email, user.Username, passwordHash);
}
user.PasswordHash = passwordHash;
}
public async Task<string> GetPasswordHashAsync(Login user, CancellationToken cancellationToken)
{
return await Task.FromResult(user.PasswordHash);
}
public async Task<bool> HasPasswordAsync(Login user, CancellationToken cancellationToken)
{
return await Task.FromResult(!string.IsNullOrEmpty(user.PasswordHash) && !string.IsNullOrEmpty(user.Salt));
}
public Task SetEmailAsync(Login user, string email, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<string> GetEmailAsync(Login user, CancellationToken cancellationToken)
{
return Task.FromResult(user.Email);
}
public async Task<bool> GetEmailConfirmedAsync(Login user, CancellationToken cancellationToken)
{
return await Task.FromResult(user.EmailConfirmed);
}
public Task SetEmailConfirmedAsync(Login user, bool confirmed, CancellationToken cancellationToken)
{
return Task.FromResult(user.EmailConfirmed = confirmed);
}
public Task<Login> FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<string> GetNormalizedEmailAsync(Login user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task SetNormalizedEmailAsync(Login user, string normalizedEmail, CancellationToken cancellationToken)
{
return Task.FromResult(user.Email = normalizedEmail.ToLower());
}
public Task SetPhoneNumberAsync(Login user, string phoneNumber, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<string> GetPhoneNumberAsync(Login user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task<bool> GetPhoneNumberConfirmedAsync(Login user, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
public Task SetPhoneNumberConfirmedAsync(Login user, bool confirmed, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
以及 Startup.cs ConfigureServices 方法:
services.AddSingleton<IUserStore<Login>, UserStore>();
我最接近的答案是这个 git 项目:https://github.com/grandchamp/Identity.Dapper
它仍在进行中,我正在与项目所有者合作进行一些改进,但对于遇到这个问题的其他人来说,现在该项目是你最好的选择。