Glo*_*Jim 5 .net c# asp.net-mvc asp.net-core
我有一个使用Identity在MVC5上构建的Web应用程序。我想将此项目转换为ASP.NET Core 2.2 Web应用程序。我创建了一个新的ASP.NET Core 2.2 Web应用程序,其身份验证设置为“个人用户帐户”,并按照以下说明将数据库添加到了项目中。然后,我在项目中添加了一个新的Identity Scaffolded项目,并添加了迁移并更新了数据库。
我注册了一个测试用户,当我检查SQL管理服务器时,我看到它为该项目创建了一个新数据库,即使我的连接字符串适用于旧数据库。
我想保留我的旧数据库,但将其转换为使用ASP.NET Core内置的新Identity Razor页面。这样做的最佳方法是什么?
我刚刚能够通过以下步骤成功地将 .NET 4.5.2 项目迁移到 .NET Core 3.1
Scaffold-DbContext根据现有数据库创建模型[1]Scaffold-DbContext [-Connection] [-Provider] [-OutputDir] [-Context] [-Schemas>] [-Tables>] [-DataAnnotations] [-Force] [-Project] [-StartupProject] [<CommonParameters>]
Run Code Online (Sandbox Code Playgroud)
从生成的上下文中删除所有与 AspNet 相关的表以及不再需要的 .cs 文件。
添加到上下文文件上base.OnModelCreating(modelBuilder);生成的方法。[2]OnModelCreating
Scaffold-DbContext [-Connection] [-Provider] [-OutputDir] [-Context] [-Schemas>] [-Tables>] [-DataAnnotations] [-Force] [-Project] [-StartupProject] [<CommonParameters>]
Run Code Online (Sandbox Code Playgroud)
Startup.cs文件上设置密码哈希器兼容模式以考虑 IdentityV2ALTER TABLE ASPNETROLES
ADD
ConcurrencyStamp VARCHAR(255) NULL,
NormalizedName VARCHAR(255) NULL
DROP TABLE AspNetUserTokens
CREATE TABLE [AspNetUserTokens] (
[UserId] NVARCHAR (450) NOT NULL,
[LoginProvider] NVARCHAR (450) NOT NULL,
[Name] NVARCHAR (450) NOT NULL,
[Value] NVARCHAR (MAX) NULL,
CONSTRAINT [PK_AspNetUserTokens]
PRIMARY KEY CLUSTERED ([UserId] ASC, [LoginProvider] ASC, [Name] ASC)
)
ALTER TABLE AspNetUsers
ADD
ConcurrencyStamp VARCHAR(255) NULL,
LockoutEnd DATETIME NULL,
NormalizedEmail VARCHAR(255) NULL,
NormalizedUserName VARCHAR(255) NULL
DROP TABLE [AspNetRoleClaims]
CREATE TABLE [AspNetRoleClaims] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[ClaimType] NVARCHAR (MAX) NULL,
[ClaimValue] NVARCHAR (MAX) NULL,
[RoleId] NVARCHAR (128) NOT NULL,
CONSTRAINT [PK_AspNetRoleClaims]
PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_AspNetRoleClaims_AspNetRoles_RoleId]
FOREIGN KEY ([RoleId])
REFERENCES [dbo].[AspNetRoles] ([Id]) ON DELETE CASCADE
)
GO
CREATE NONCLUSTERED INDEX [IX_AspNetRoleClaims_RoleId]
ON [AspNetRoleClaims]([RoleId] ASC)
ALTER TABLE AspNetUserLogins
ADD ProviderDisplayName VARCHAR(255) NULL
UPDATE AspNetUsers SET NormalizedEmail = UPPER(Email), NormalizedUserName = UPPER(UserName)
WHERE NormalizedEmail IS NULL
Run Code Online (Sandbox Code Playgroud)
升级标识表后,您可能要更新现有用户的密码哈希。表中的一些新列AspNetUsers将具有NULL值。首先运行:
UPDATE AspNetUsers SET NormalizedEmail = UPPER(Email), NormalizedUserName = UPPER(Email)
WHERE NormalizedEmail IS NULL
Run Code Online (Sandbox Code Playgroud)
实际上,NormalizedUserName已使用大写电子邮件进行更新。
我们需要一种方法来区分哪些用户正在使用新的哈希版本。
一种方法是向IdentityUser添加新属性:
public class ApplicationUser : IdentityUser
{
public PasswordHashVersion HashVersion { get; set; }
public ApplicationUser()
{
this.HashVersion = PasswordHashVersion.Core;
}
}
public enum PasswordHashVersion
{
OldMvc,
Core
}
Run Code Online (Sandbox Code Playgroud)
现有用户的默认值将PasswordHashVersion为零(OldMvc),新注册的用户的默认值将为1(Core)。如果您有一种更聪明的方式来检测哈希是来自新算法还是旧算法,则不需要此方法。
然后,我们创建一个自定义的PasswordHash,它使用旧的默认哈希算法实现:
public class OldMvcPasswordHasher : PasswordHasher<ApplicationUser>
{
public override PasswordVerificationResult VerifyHashedPassword(ApplicationUser user, string hashedPassword, string providedPassword)
{
// if it's the new algorithm version, delegate the call to parent class
if (user.HashVersion == PasswordHashVersion.Core)
return base.VerifyHashedPassword(user, hashedPassword, providedPassword);
byte[] buffer4;
if (hashedPassword == null)
{
return PasswordVerificationResult.Failed;
}
if (providedPassword == null)
{
throw new ArgumentNullException("providedPassword");
}
byte[] src = Convert.FromBase64String(hashedPassword);
if ((src.Length != 0x31) || (src[0] != 0))
{
return PasswordVerificationResult.Failed;
}
byte[] dst = new byte[0x10];
Buffer.BlockCopy(src, 1, dst, 0, 0x10);
byte[] buffer3 = new byte[0x20];
Buffer.BlockCopy(src, 0x11, buffer3, 0, 0x20);
using (Rfc2898DeriveBytes bytes = new Rfc2898DeriveBytes(providedPassword, dst, 0x3e8))
{
buffer4 = bytes.GetBytes(0x20);
}
if (AreHashesEqual(buffer3, buffer4))
{
user.HashVersion = PasswordHashVersion.Core;
return PasswordVerificationResult.SuccessRehashNeeded;
}
return PasswordVerificationResult.Failed;
}
private bool AreHashesEqual(byte[] firstHash, byte[] secondHash)
{
int _minHashLength = firstHash.Length <= secondHash.Length ? firstHash.Length : secondHash.Length;
var xor = firstHash.Length ^ secondHash.Length;
for (int i = 0; i < _minHashLength; i++)
xor |= firstHash[i] ^ secondHash[i];
return 0 == xor;
}
}
Run Code Online (Sandbox Code Playgroud)
此类继承了新的Identity Core PasswordHasher。如果用户的密码哈希版本已经在使用新算法(例如HashVersion = Core),那么我们只需调用PasswordHasher使用新算法的基本方法即可。否则,请使用旧的身份算法来验证密码。
如果密码匹配,则将用户密码哈希版本更新为Core,然后返回PasswordVerificationResult.SuccessRehashNeeded以使用新算法强制更新现有哈希。
最后,您需要确保PasswordHasher正在使用您的自定义。添加到Startup.cs里面ConfigureServices:
// Replace the existing scoped IPasswordHasher<> implementation
services.Replace(new ServiceDescriptor(
serviceType: typeof(IPasswordHasher<ApplicationUser>),
implementationType: typeof(OldMvcPasswordHasher),
ServiceLifetime.Scoped));
Run Code Online (Sandbox Code Playgroud)
这必须以任何呼叫后加入
AddIdentity,AddDefaultIdentity或AddIdentityCore。
当您的用户进行身份验证时,这将缓慢更新密码哈希。
| 归档时间: |
|
| 查看次数: |
823 次 |
| 最近记录: |