直接插入aspnet_membership用户后登录失败及密码显示乱码问题求助
aspnet_membership用户后登录失败及密码显示乱码问题求助
兄弟,我帮你捋捋你遇到的两个问题:密码显示乱码和登录失败,其实根源都是没完全匹配SqlMembershipProvider的密码哈希逻辑,咱们一步步解决:
先说说密码显示乱码的原因
你看,aspnet_Membership表的Password字段类型是NVARCHAR(128),不是VARBINARY!你直接把HASHBYTES生成的二进制哈希值插进去,SQL Server会自动把二进制数据转成字符串,但这个转换过程因为编码不匹配就出现了中文乱码——这其实只是显示层面的问题,核心还是登录失败的逻辑错误,咱们重点解决这个。
登录失败的核心原因
SqlMembershipProvider的密码哈希逻辑不是简单的SHA2_256(密码+salt字符串),它的标准流程是这样的:
- 把salt转成字节数组(通常是Base64编码字符串对应的字节)
- 把密码转成Unicode(UTF-16LE)字节数组
- 按顺序拼接salt字节数组和密码字节数组
- 用配置的哈希算法(默认是SHA1,如果你改了是SHA2_256就用这个)计算哈希
- 把哈希结果转成Base64字符串存在
Password字段;salt的Base64字符串存在PasswordSalt字段
你的代码犯了两个关键错误:
- 直接把二进制哈希值插入NVARCHAR的
Password字段,而不是转成Provider期望的Base64字符串 - 哈希过程是拼接字符串再哈希,而不是拼接字节数组再哈希,这会导致哈希结果和Provider验证时的结果完全不一致
解决方法
方法一:最稳妥的方式——用.NET代码创建用户
直接在你的应用里调用Membership.CreateUser()方法,这会自动帮你完成所有哈希和表插入操作,完全符合Provider逻辑,不会出问题。比如:
MembershipCreateStatus status; MembershipUser user = Membership.CreateUser("admin", "P@ssw0rd123", "admin@example.com", null, null, true, out status);
方法二:必须用SQL手动插入的话,模拟Provider逻辑
下面是符合标准流程的SQL代码,替换成你的应用名和用户名就能用:
DECLARE @ApplicationName NVARCHAR(256) = '你的应用名称'; -- 替换成实际的ApplicationName DECLARE @UserName NVARCHAR(256) = 'admin'; -- 要创建的用户名 DECLARE @Password NVARCHAR(128) = 'P@ssw0rd123'; -- 获取对应的ApplicationId DECLARE @ApplicationId UNIQUEIDENTIFIER = (SELECT ApplicationId FROM aspnet_Applications WHERE ApplicationName = @ApplicationName); -- 生成随机salt:转成字节数组再转Base64字符串(和Provider逻辑一致) DECLARE @SaltBytes VARBINARY(16) = CAST(NEWID() AS VARBINARY(16)); DECLARE @Salt NVARCHAR(24) = sys.fn_varbintobase64(@SaltBytes); -- 把密码转成Unicode字节数组 DECLARE @PasswordBytes VARBINARY(MAX) = CAST(@Password AS VARBINARY(MAX)); -- 拼接salt字节 + 密码字节 DECLARE @CombinedBytes VARBINARY(MAX) = @SaltBytes + @PasswordBytes; -- 计算SHA2_256哈希(如果你的Provider配置的是SHA1,就改成'SHA1') DECLARE @HashedBytes VARBINARY(64) = HASHBYTES('SHA2_256', @CombinedBytes); -- 把哈希结果转成Base64字符串,存入Password字段 DECLARE @HashedPassword NVARCHAR(88) = sys.fn_varbintobase64(@HashedBytes); -- 生成唯一UserId DECLARE @UserId UNIQUEIDENTIFIER = NEWID(); -- 别忘了先插入aspnet_Users表!Membership表依赖这个表的UserId INSERT INTO aspnet_Users (ApplicationId, UserId, UserName, LoweredUserName, IsAnonymous, LastActivityDate) VALUES (@ApplicationId, @UserId, @UserName, LOWER(@UserName), 0, GETDATE()); -- 插入aspnet_Membership表 INSERT INTO aspnet_Membership ( ApplicationId, UserId, Password, PasswordSalt, IsApproved, IsLockedOut, CreateDate, LastLoginDate, LastPasswordChangedDate, LastLockoutDate, FailedPasswordAttemptCount, FailedPasswordAttemptWindowStart, FailedPasswordAnswerAttemptCount, FailedPasswordAnswerAttemptWindowStart ) VALUES ( @ApplicationId, @UserId, @HashedPassword, @Salt, 1, 0, GETDATE(), GETDATE(), GETDATE(), '17540101', 0, GETDATE(), 0, GETDATE() );
执行完这个代码后,你再查询aspnet_Membership表,Password字段会显示正常的Base64字符串,不会乱码,而且登录时也能正确验证了。
另外提醒下:如果你的MembershipProvider配置里的哈希算法不是SHA2_256(默认是SHA1),记得把代码里的HASHBYTES('SHA2_256', ...)改成对应的算法名称。
备注:内容来源于stack exchange,提问作者Mahmoud Ashraf




