Проверьте токен с помощью ConfirmEmailAsyn c (), который был создан с помощью GenerateEmailConfirmationTokenAsyn c () в другом домене - InvalidToken - PullRequest
0 голосов
/ 24 января 2020

У меня есть два Asp. Net Core 2.1 приложения.

Один сайт на firstdomain.com , который должен иметь возможность создавать / регистрировать / управлять учетными записями пользователей в этом же домене, а также создавать / регистрировать / управлять учетными записями пользователей на сайте по адресу seconddomain.com .

Создание / регистрация пользователей с firstdomain.com для пользователей на firstdomain.com работает безупречно через -

  1. Отправить письмо от контроллера на firstdomain.com включая токен -

string token = await userManager.GenerateEmailConfirmationTokenAsync(user);

Пользователь получает электронное письмо с кнопкой, которая ссылается на страницу ConfirmEmail на firstdomain.com , где токен проверяется с помощью -
var user = await userManager.FindByIdAsync(userId);
var result = await userManager.ConfirmEmailAsync(user, HttpUtility.UrlDecode(token));

Подтверждение электронной почты пользователя , они установили свой пароль и вошли на сайт. на firstdomain.com .

Однако ...

Создание / регистрация пользователей из firstdomain.com для пользователей на seconddomain.com обрабатывается следующим образом -

  1. Отправка электронной почты с контроллера на firstdomain.com , включая токен -

string token = await userManager.GenerateEmailConfirmationTokenAsync(user);

Пользователь получает электронное письмо с кнопкой, которая ссылается на страницу ConfirmEmail на seconddomain.com , где токен фактически помечен как недействительный через -
var user = await userManager.FindByIdAsync(userId);
var result = await userManager.ConfirmEmailAsync(user, HttpUtility.UrlDecode(token));

Создание / регистрация пользователей из firstdomain.com , чтобы быть пользователями на seconddomain.com не работает , и журналы показывают - VerifyUserTokenAsyn c ( ) не удалось с целью: EmailConfirmation для пользователя XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX

Оба приложения работают на одном сервере.

Соответствующий код Startup.cs

Оба сайта используют эти же настройки в соответствующих файлах Startup.cs -

            // aspNet identity setup
            services.AddIdentity<ApplicationUser, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders();
            services.AddScoped<ApplicationSignInManager>();
            // access User/Identity
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

            // set the identity config options with our custom helper
            services.Configure<IdentityOptions> 
            (ApplicationConfigHelper.SetIdentityOptions);
    services.ConfigureApplicationCookie(ApplicationConfigHelper.SetCookieOptions);

ApplicationConfigHelper. cs

public static class ApplicationConfigHelper
    {
        public static object ActionRequest { get; private set; }

        public static void SetIdentityOptions(IdentityOptions options)
        {
            // password setup
            options.Password.RequiredLength = 8;
            options.Password.RequireNonAlphanumeric = true;
            options.Password.RequireDigit = true;
            options.Password.RequireLowercase = true;
            options.Password.RequireUppercase = true;
            options.Password.RequiredUniqueChars = 6;

            // lock out settings
            options.Lockout.AllowedForNewUsers = true;
            options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
            options.Lockout.MaxFailedAccessAttempts = 5;

            // user settings 
            options.User.RequireUniqueEmail = true;

            // sign in settings
            options.SignIn.RequireConfirmedEmail = true;
            options.SignIn.RequireConfirmedPhoneNumber = false;
        }

        public static void SetCookieOptions(CookieAuthenticationOptions options)
        {
            options.Cookie.HttpOnly = true;
            options.LoginPath = "/Account/Login";
            options.AccessDeniedPath = "/Account/AccessDenied";
            options.ExpireTimeSpan = TimeSpan.FromDays(1.0);
            options.SlidingExpiration = true;
            options.Cookie.SameSite = SameSiteMode.Strict;
        }
    }

ApplicationUser.cs

 public class ApplicationUser : IdentityUser
    {
        public string AccountNumber { get; set; }
        public DateTime? Enrolled { get; set; }

        /// <summary>
        /// Intended to prevent users from spamming the resend invitation email 
        /// link.
        /// </summary>
        public DateTime? InvitationExpirationDate { get; set; }
    }

Ответы [ 2 ]

0 голосов
/ 29 января 2020

ОБНОВЛЕНИЕ

Это оказалось идеальным вариантом использования для JWT.

Вот как я решил эту проблему -

Из контроллера на firstdomain.com , при отправке пользователю ссылки на регистрацию на seconddomain.com я включаю JWT следующим образом -

// use a jwt token that can be verified on another domain
   var token = jsonWebTokenService.GetEncryptedToken(new ClaimsIdentity(GetClaimsList(user.Id)), TimeSpan.FromMinutes(10));
 private IList<Claim> GetClaimsList(string id)
        {
            return new List<Claim>() {
                new Claim(ClaimTypes.Name, id),
                new Claim(ClaimTypes.UserData, id),
                new Claim(ClaimTypes.Role, "ROLESTRING")
            };
        }

Из JsonWebTokenService.cs -

public string GetEncryptedToken(ClaimsIdentity subject, TimeSpan timeSpan)
        {
            // setup credentials
            var signingCreds = new SigningCredentials(signatureKey, SecurityAlgorithms.HmacSha256);
            var encryptionCreds = new EncryptingCredentials(encryptionKey,
                SecurityAlgorithms.Aes128KW, SecurityAlgorithms.Aes128CbcHmacSha256);

            // claims identity for jwt creation
            var handler = new JwtSecurityTokenHandler();
            var utcNow = DateTime.UtcNow;

            var token = handler.CreateJwtSecurityToken(jwtSettings.Issuer, jwtSettings.Issuer, subject,
                utcNow, utcNow.AddMilliseconds(timeSpan.TotalMilliseconds), utcNow, signingCreds, encryptionCreds);

            return handler.WriteToken(token);
        }

* Примечание. Я вручную создал signatureKey и encryptionKey с помощью отдельного консольного приложения, в котором использовались безопасные / проверенные библиотеки шифрования, такие как RNGCryptoServiceProvider () и HMACSHA256. () и я надежно хранил эти значения в переменных среды на сервере для обоих доменов, а также для секретов. json для каждого проекта.

Ссылка для регистрации действительна в течение 10 минут (время жизни JWT).

Из контроллера на seconddomain.com я проверяю JWT -

            var user = await userManager.FindByIdAsync(userId);

            try
            {
                var principal = jsonWebTokenService.ProcessEncryptedToken(code);

                var name = principal.FindFirstValue(ClaimTypes.Name);
                var role = principal.FindFirstValue(ClaimTypes.Role);

                if (name != user.Id || role != "ROLESTRING")
                    throw new ArgumentException("User not found.");

                user.EmailConfirmed = true;
                await userManager.UpdateAsync(user);
                await signInManager.SignOutAsync();
                return RedirectToAction("CompleteRegistration", new { userId = userId, code = code });
            }
            catch (Exception ex)
            {
                logger.LogWarning(ex, "Failed to confirm email for {UserId}", userId);
                return BadRequest();
            }

Снова, из JsonWebTokenService.cs, я проверяю JWT -

public ClaimsPrincipal ProcessEncryptedToken(string token)
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var validationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                ValidateIssuer = true,
                IssuerSigningKey = signatureKey,
                ValidIssuer = jwtSettings.Issuer,
                ValidateAudience = true,
                ValidAudience = jwtSettings.Issuer,
                TokenDecryptionKey = encryptionKey,
                ClockSkew = TimeSpan.Zero
            };

            // throws exceptions if the token is no longer valid
            return tokenHandler
                .ValidateToken(token, validationParameters, out SecurityToken validatedToken);
        }

Когда ток ru успешно подтвержден, пользователь перенаправлен для завершения регистрации.

Надеюсь, это поможет кому-то, кто может застрять в подобной проблеме. Существует много информации о JWT, если вы проводите исследования. Но это заняло у меня несколько часов, чтобы придумать это, поскольку не было много информации об использовании JWT для проверки регистрации электронной почты. JWT часто используются для аутентификации ПОСЛЕ , когда пользователь уже ввел действительные учетные данные на сайте. Это решение предоставило нам возможность проверить регистрацию электронной почты в разных доменах в качестве альтернативы ASP. NET Core Identity UserManager.

0 голосов
/ 24 января 2020

Хотите ли вы, чтобы ваши пользователи автоматически имели доступ к обоим сайтам?

В стандартной реализации проверки токенов используется случайное значение для каждого пользователя, которое будет храниться в базе данных. Оба ваших приложения хранят информацию о пользователях в одной и той же базе данных?

Если вы не хотите предоставлять обоим приложениям полный доступ к одной и той же базе данных, вы можете внедрить службу замены IUserSecurityStampStore, чтобы отслеживать эти случайные пользовательские секреты для обоих сайтов. Или извлеките пользовательские «секреты» детерминированным способом c, хэшируя какое-то другое секретное значение, известное обоим сайтам, однако это имеет другие последствия для безопасности, которые вам необходимо учитывать.

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

или go маршрут OAuth и генерировать некоторую форму токенов-носителей из первого домена, который второй домен может проверить .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...