Как я могу получить пользователя с токена сброса пароля в ASP. NET Core? - PullRequest
0 голосов
/ 17 января 2020

У меня есть ASP. NET Core 2.1 веб-приложение, и я добавляю функцию забытого пароля. Я рассмотрел несколько примеров, и они, похоже, используют один из двух подходов. Первый подход заключается в том, чтобы включить либо идентификатор пользователя, либо адрес электронной почты пользователя в URL-адрес для сброса пароля вместе с токеном для сброса пароля. Второй подход заключается в том, чтобы включить в маркер сброса пароля только маркер сброса пароля, а затем потребовать от пользователя ввода идентифицирующей информации (например, электронной почты) при попытке изменить пароль ( Пример двоичного интеллекта ). Есть ли способ найти пользователя, получив только маркер сброса пароля?

Руководитель группы попросил меня передать только токен в URL для сброса пароля, а затем найти пользователя. Мои первоначальные исследования заставляют меня поверить, что мне придется вручную вести учет идентификатора пользователя и токена, но я надеюсь, что есть что-то встроенное. Я просмотрел документацию ASP. NET Core UserManager , но не нашел методов для извлечения пользователя для данного токена.

Вот пример кода, встраивающего идентификатор пользователя в URL-адрес для сброса пароля ( Microsoft Password Recovery Do c):

var code = await _userManager.GeneratePasswordResetTokenAsync(user);
var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);

Ответы [ 2 ]

2 голосов
/ 22 января 2020

Есть способ получить UserId из токена сброса пароля, но, на мой взгляд, это сложно и много работы.

Какие значения по умолчанию

Если у вас есть некоторые коды, такие как следующий,

services.AddIdentity<AppUser, AppRole>(options =>
{
    ...
}
.AddEntityFrameworkStores<AppIdentityDbContext>()
.AddDefaultTokenProviders();

последняя строка .AddDefaultTokenProviders() добавляет 4 провайдера токенов по умолчанию , которые используются для генерации токенов для сброса паролей, смены электронной почты и изменения параметров номера телефона и для генерации токенов двухфакторной аутентификации в конвейер:

  1. DataProtectorTokenProvider
  2. PhoneNumberTokenProvider
  3. EmailTokenProvider
  4. AuthenticatorTokenProvider

Первый, DataProtectorTokenProvider, это то, что мы ищем. Он использует защиту данных для сериализации / шифрования этих токенов.

А в DataProtectorTokenProvider его защитник имеет значение по умолчанию для имени «DataProtectorTokenProvider» .

Как токены генерируются

Если вы посмотрите на GenerateAsync() метод внутри DataProtectorTokenProvider, вы можете сказать, что токен состоит из:

  • Ut c метка времени создания токена (DateTimeOffset.UtcNow)
  • userId
  • Строка назначения
  • Метка безопасности, если поддерживается

Метод генерирования объединяет все эти данные, преобразует их в байтовый массив и вызывает защитник внутри для защиты / шифрования полезной нагрузки. Наконец, полезная нагрузка преобразуется в строку base 64.

Как получить идентификатор пользователя

Чтобы получить userId из токена, вам необходимо выполнить обратную инженерию:

  • Преобразование токена из строки base 64 обратно в байтовый массив
  • Вызов защитника внутри для снятия защиты / дешифрования байтового массива
  • Считывание метки времени Ut c
  • Чтение userId

Сложность здесь в том, как получить тот же DataProtector, используемый для генерации этих токенов!

Как получить Data Protector по умолчанию

Поскольку по умолчанию DataProtectorTokenProvider встроено в конвейер, я могу думать только о том, чтобы получить то же самое DataProtector, - это использовать DataProtectorTokenProvider по умолчанию, чтобы создать протектор с таким же имя по умолчанию «DataProtectorTokenProvider», используемое для генерации токенов!

public class GetResetPasswordViewModelHandler : IRequestHandler<...>
{
    ...
    private readonly IDataProtector _dataProtector;

    public GetResetPasswordViewModelHandler(...,
       IDataProtectionProvider dataProtectionProvider)
    {
        ...
        _dataProtector = dataProtectionProvider.CreateProtector("DataProtectorTokenProvider");
        // OR
        // dataProtectionProvider.CreateProtector(new DataProtectionTokenProviderOptions().Name);
    }

    public async Task<ResetPasswordViewModel> Handle(GetResetPasswordViewModel query, ...)
    {
        // The password reset token comes from query.ResetToken
        var resetTokenArray = Convert.FromBase64String(query.ResetToken);

        var unprotectedResetTokenArray = _dataProtector.Unprotect(resetTokenArray);

        using (var ms = new MemoryStream(unprotectedResetTokenArray))
        {
            using (var reader = new BinaryReader(ms))
            { 
                // Read off the creation UTC timestamp
                reader.ReadInt64();

                // Then you can read the userId!
                var userId = reader.ReadString();

                ...
            }
        }

        ...
    }
}

Снимок экрана: enter image description here

Мои 2 цента

Кажется, что это большая работа, просто попробуйте прочитать userId с токена сброса пароля. Я понимаю, что ваш руководитель группы, вероятно, не хочет показывать идентификатор пользователя в ссылке для сброса пароля, или (с) он считает, что это избыточно, поскольку маркер сброса имеет userId.

Если вы используете целое число, представляющее userId, и не хочу выставлять это для публикации c, я бы изменил его на GUID.

Если вам нужно использовать целое число в качестве userId, я бы просто создайте столбец типа unique_identifier из профиля пользователя (я бы назвал его PublicToken) и используйте его для идентификации пользователя для всех важных вопросов.

var callbackUrl = Url.Action("resetPassword", "account", new
{
    area = "",
    rt = passwordResetToken,   // reset token
    ut = appUser.Id            // user token, use GUID user id or appUser.PublicToken
}, protocol: Request.Scheme);

1 голос
/ 19 января 2020

Я полагаю, что вы никак не можете сделать это, если вы можете передать электронную почту пользователя, а затем найти его в своем коде. 1006 *

...