在从ASP.NET成员身份切换到ASP.NET Core身份

时间:2018-12-06 21:28:37

标签: asp.net-core asp.net-identity asp.net-membership identityserver4

我的公司计划将我们的应用程序从.NET Framework升级到.NET Core,并将其从ASP.NET Membership升级到ASP.NET Core Identity服务器。我在此here上找到了一篇有用的文章。

但是,有一个具有大量含义的子注释:

  

此脚本完成后,创建了ASP.NET Core Identity应用   较早时已填充有Membership用户。用户需要更改他们的   登录前输入密码。

作为迁移的一部分,我们不能要求600,000用户更改其密码。但是,会员密码是单向散列的,因此我们无法检索它们然后进行迁移。因此,我想知道如何使用新的Identity Server方法来维护现有用户的密码。

2 个答案:

答案 0 :(得分:1)

我是最近才这样做的。

我们有一个旧的.net成员资格系统,需要将大约1万名用户导入asp.net身份。当我从系统中复制所有用户并带来他们的旧密码时,我首先在asp .net身份核心用户表中创建了一个额外的列。

然后在用户首次登录时。我首先检查了旧密码是否存在,然后对它进行了验证,并在asp上更新了密码。网身份核心并删除了旧密码。这样,所有用户都将密码移植到了新系统中,甚至没有意识到。

我将尝试解释我是如何做到的,但是代码有点疯狂。

我实际上在applicationuser表中添加了两列

public string LegacyPasswordHash { get; set; }
public string LegacyPasswordSalt { get; set; }

ApplicationSignInManager-> CheckPasswordSignInAsync方法检查用户是否为旧用户

ApplicationSignInManager

public override async Task<SignInResult> CheckPasswordSignInAsync(ApplicationUser user, string password, bool lockoutOnFailure)
        {
        ........

            if (user.IsLegacy)
            {
                Logger.LogDebug(LoggingEvents.ApplicationSignInManagerCheckPasswordSignInAsync, "[user.Id: {user.Id}] is legacy.", user.Id);
                var results = await new LoginCommand(_logger, _userManager, user, password, lockoutOnFailure).Execute();
                if (results.Succeeded)
                {
                    await ResetLockout(user);
                    return SignInResult.Success;
                }
            }
            else if (await UserManager.CheckPasswordAsync(user, password))
            {
                await ResetLockout(user);
                return SignInResult.Success;
            }

            ........
        }

登录命令

 public class LoginCommand
    {
        private readonly ILogger _logger;
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly ApplicationUser _user;
        private readonly string _password;
        private readonly bool _shouldLockout;

        public LoginCommand(ILogger logger, UserManager<ApplicationUser> userManager, ApplicationUser user, string password, bool shouldLockout)
        {
            _logger = logger;
            _userManager = userManager;
            _user = user;
            _password = password;
            _shouldLockout = shouldLockout;
        }

        public async Task<SignInResult> Execute()
        {
            _logger.LogInformation($"Found User: {_user.UserName}");
            if (_user.IsLegacy)
                return await new LegacyUserCommand(_logger, _userManager, _user, _password, _shouldLockout).Execute();
            if (await _userManager.CheckPasswordAsync(_user, _password))
                return await new CheckTwoFactorCommand(_logger, _userManager, _user).Execute();
            if (_shouldLockout)
            {
                return await new CheckLockoutCommand(_logger, _userManager, _user).Execute();
            }
            _logger.LogDebug($"Login failed for user {_user.Email} invalid password");
            return SignInResult.Failed;
        }
    }

LegacyUserCommand

  public class LegacyUserCommand
    {
        private readonly ILogger _logger;
        private readonly UserManager<ApplicationUser> _userManager;

        private readonly ApplicationUser _user;
        private readonly string _password;
        private bool _shouldLockout;

        public LegacyUserCommand(ILogger logger, UserManager<ApplicationUser> userManager, ApplicationUser user, string password, bool shouldLockout)
        {
            _logger = logger;
            _userManager = userManager;
            _user = user;
            _password = password;
            _shouldLockout = shouldLockout;
        }

        public async Task<SignInResult> Execute()
        {
            try
            {
                if (_password.EncodePassword(_user.LegacyPasswordSalt) == _user.LegacyPasswordHash)
                {
                    _logger.LogInformation(LoggingEvents.LegacyUserCommand, "Legacy User {_user.Id} migrating password.", _user.Id);
                    await _userManager.AddPasswordAsync(_user, _password);
                    _user.SecurityStamp = Guid.NewGuid().ToString();
                    _user.LegacyPasswordHash = null;
                    _user.LegacyPasswordSalt = null;
                    await _userManager.UpdateAsync(_user);
                    return await new CheckTwoFactorCommand(_logger, _userManager, _user).Execute();
                }
                if (_shouldLockout)
                {
                    _user.SecurityStamp = Guid.NewGuid().ToString();
                    await _userManager.UpdateAsync(_user);
                    _logger.LogInformation(LoggingEvents.LegacyUserCommand, "Login failed for Legacy user {_user.Id} invalid password. (LockoutEnabled)", _user.Id);
                    await _userManager.AccessFailedAsync(_user);
                    if (await _userManager.IsLockedOutAsync(_user))
                        return SignInResult.LockedOut;
                }

                _logger.LogInformation(LoggingEvents.LegacyUserCommand, "Login failed for Legacy user {_user.Id} invalid password", _user.Id);
                return SignInResult.Failed;
            }
            catch (Exception e)
            {
                _logger.LogError(LoggingEvents.LegacyUserCommand, "LegacyUserCommand Failed for [_user.Id: {_user.Id}]  [Error Message: {e.Message}]", _user.Id, e.Message);
                _logger.LogTrace(LoggingEvents.LegacyUserCommand, "LegacyUserCommand Failed for [_user.Id: {_user.Id}] [Error: {e}]", _user.Id, e);
                return SignInResult.Failed;
            }
        }
    }

顶部提示:[SecurityStamp]不能为NULL!

答案 1 :(得分:0)

我们最近从各种旧系统中迁移,由于它们都使用了各种形式的哈希密码,因此我们没有尝试将逻辑移植到端口上,而是自定义了密码身份验证代码,以允许其对由每个旧系统。从这样的系统迁移的每个用户都有针对它存储的API URL。

当迁移的用户首次登录时,我们会调出该服务(该服务本身已使用承载令牌和受限制的集成范围保护),以进行首次密码验证。如果获得成功响应,那么我们将以我们自己的格式对密码进行哈希处理,并且将被永久使用。

这样做的缺点是您必须永久保持旧系统(使用新的API固定)。既然所有这些都是.Net,那么假设您可以在.Net Core中运行一个旧的哈希方案,就可以通过保留所有进程内的信息并将迁移的用户哈希密码复制到新数据库中而获得更好的表现。