public async Task <ActionResult> Login([FromForm] Login login, [FromQuery] string returnUrl)
        {
            TryValidateModel(login);

            // This required for populate fields on form on post-back
            WorkContext.Form = Form.FromObject(login);

            if (!ModelState.IsValid)
            {
                return(View("customers/login", WorkContext));
            }
            login.UserName = login.UserName?.Trim();

            var user = await _signInManager.UserManager.FindByNameAsync(login.UserName);

            if (user == null)
            {
                WorkContext.Form.Errors.Add(SecurityErrorDescriber.LoginFailed());
                return(View("customers/login", WorkContext));
            }

            if (!new CanUserLoginToStoreSpecification(user).IsSatisfiedBy(WorkContext.CurrentStore))
            {
                if (login.ForceLoginToAccountStore)
                {
                    var store       = WorkContext.AllStores.First(x => x.Id == user.StoreId);
                    var url         = HttpContext.Request.GetEncodedUrl();
                    var redirectUrl = _urlBuilder.ToStoreAbsolute(url, store, store.DefaultLanguage);
                    return(RedirectPreserveMethod(redirectUrl));
                }

                WorkContext.Form.Errors.Add(SecurityErrorDescriber.UserCannotLoginInStore());
                return(View("customers/login", WorkContext));
            }

            if (new IsUserLockedOutSpecification().IsSatisfiedBy(user))
            {
                return(View("lockedout", WorkContext));
            }

            if (new IsUserSuspendedSpecification().IsSatisfiedBy(user))
            {
                WorkContext.Form.Errors.Add(SecurityErrorDescriber.AccountIsBlocked());
                return(View("customers/login", WorkContext));
            }

            var loginResult = await _signInManager.PasswordSignInAsync(login.UserName, login.Password, login.RememberMe, lockoutOnFailure : true);

            if (loginResult.Succeeded)
            {
                await _publisher.Publish(new UserLoginEvent(WorkContext, user));

                if (new IsUserPasswordExpiredSpecification().IsSatisfiedBy(user))
                {
                    //the sign in operation doesn't change the current request user principal, this only happens on incoming requests when the cookie or bearer token is set.
                    //Need to manually set User in the HttpContext to avoid issues such as Antiforegery cookies generated for anonymous within this request despite the user has already signed in.
                    HttpContext.User = await _signInManager.ClaimsFactory.CreateAsync(user);

                    WorkContext.Form = Form.FromObject(new ResetPassword
                    {
                        Token    = await _signInManager.UserManager.GenerateUserTokenAsync(user, TokenOptions.DefaultProvider, "ResetPassword"),
                        Email    = user.Email,
                        UserName = user.UserName
                    });
                    return(View("customers/reset_password", WorkContext));
                }

                return(StoreFrontRedirect(returnUrl));
            }

            if (loginResult.RequiresTwoFactor)
            {
                var selectedProvider = _options.TwoFactorAuthenticationNotificationGateway;

                var userManager = _signInManager.UserManager;
                var code        = await userManager.GenerateTwoFactorTokenAsync(user, selectedProvider);

                if (string.IsNullOrWhiteSpace(code))
                {
                    WorkContext.Form.Errors.Add(SecurityErrorDescriber.OperationFailed());
                    return(View("customers/login", WorkContext));
                }

                NotificationBase twoFactorNotification = null;
                var veryfyCodeViewModel = new VerifyCodeViewModel {
                    Provider = selectedProvider, ReturnUrl = returnUrl, RememberMe = login.RememberMe, Username = login.UserName
                };

                if (veryfyCodeViewModel.Provider.EqualsInvariant("Phone"))
                {
                    var phoneNumber = await userManager.GetPhoneNumberAsync(user);

                    if (string.IsNullOrEmpty(phoneNumber))
                    {
                        // Do not tell we have this user without phone
                        WorkContext.Form.Errors.Add(SecurityErrorDescriber.OperationFailed());
                        return(View("customers/login", WorkContext));
                    }

                    twoFactorNotification = new TwoFactorSmsNotification(WorkContext.CurrentStore.Id, WorkContext.CurrentLanguage)
                    {
                        Token = code, Recipient = phoneNumber,
                    };
                }
                else // "Email"
                {
                    twoFactorNotification = new TwoFactorEmailNotification(WorkContext.CurrentStore.Id, WorkContext.CurrentLanguage)
                    {
                        Token     = code,
                        Sender    = WorkContext.CurrentStore.Email,
                        Recipient = GetUserEmail(user)
                    };
                }

                var sendingResult = await SendNotificationAsync(twoFactorNotification);

                if (sendingResult.IsSuccess != true)
                {
                    WorkContext.Form.Errors.Add(SecurityErrorDescriber.ErrorSendNotification(sendingResult.ErrorMessage));
                    return(View("customers/login", WorkContext));
                }

                WorkContext.Form = Form.FromObject(veryfyCodeViewModel);

                return(View("customers/verify_code", WorkContext));
            }

            WorkContext.Form.Errors.Add(SecurityErrorDescriber.LoginFailed());

            return(View("customers/login", WorkContext));
        }
Beispiel #2
0
        public async Task <ActionResult> Login([FromForm] Login login, string returnUrl)
        {
            TryValidateModel(login);

            // This required for populate fields on form on post-back
            WorkContext.Form = Form.FromObject(login);

            if (!ModelState.IsValid)
            {
                return(View("customers/login", WorkContext));
            }
            login.UserName = login.UserName?.Trim();

            var loginResult = await _signInManager.PasswordSignInAsync(login.UserName, login.Password, login.RememberMe, lockoutOnFailure : true);

            if (loginResult.Succeeded)
            {
                var user = await _signInManager.UserManager.FindByNameAsync(login.UserName);

                // Check that current user can sing in to current store
                if (new CanUserLoginToStoreSpecification(user).IsSatisfiedBy(WorkContext.CurrentStore) && new IsUserSuspendedSpecification().IsSatisfiedBy(user) == false)
                {
                    await _publisher.Publish(new UserLoginEvent(WorkContext, user));

                    return(StoreFrontRedirect(returnUrl));
                }
                else
                {
                    WorkContext.Form.Errors.Add(SecurityErrorDescriber.UserCannotLoginInStore());
                    await _signInManager.SignOutAsync();

                    loginResult = Microsoft.AspNetCore.Identity.SignInResult.NotAllowed;
                }
            }

            if (loginResult.RequiresTwoFactor)
            {
                var user = await _signInManager.UserManager.FindByNameAsync(login.UserName);

                if (user == null)
                {
                    WorkContext.Form.Errors.Add(SecurityErrorDescriber.OperationFailed());
                    return(View("customers/login", WorkContext));
                }

                var selectedProvider = _options.TwoFactorAuthenticationNotificationGateway;

                var userManager = _signInManager.UserManager;
                var code        = await userManager.GenerateTwoFactorTokenAsync(user, selectedProvider);

                if (string.IsNullOrWhiteSpace(code))
                {
                    WorkContext.Form.Errors.Add(SecurityErrorDescriber.OperationFailed());
                    return(View("customers/login", WorkContext));
                }

                NotificationBase twoFactorNotification = null;
                var veryfyCodeViewModel = new VerifyCodeViewModel {
                    Provider = selectedProvider, ReturnUrl = returnUrl, RememberMe = login.RememberMe, Username = login.UserName
                };

                if (veryfyCodeViewModel.Provider.EqualsInvariant("Phone"))
                {
                    var phoneNumber = await userManager.GetPhoneNumberAsync(user);

                    if (string.IsNullOrEmpty(phoneNumber))
                    {
                        // Do not tell we have this user without phone
                        WorkContext.Form.Errors.Add(SecurityErrorDescriber.OperationFailed());
                        return(View("customers/login", WorkContext));
                    }

                    twoFactorNotification = new TwoFactorSmsNotification(WorkContext.CurrentStore.Id, WorkContext.CurrentLanguage)
                    {
                        Token     = code,
                        Recipient = phoneNumber,
                    };
                }
                else // "Email"
                {
                    twoFactorNotification = new TwoFactorEmailNotification(WorkContext.CurrentStore.Id, WorkContext.CurrentLanguage)
                    {
                        Token     = code,
                        Sender    = WorkContext.CurrentStore.Email,
                        Recipient = GetUserEmail(user)
                    };
                }
                var sendingResult = await SendNotificationAsync(twoFactorNotification);

                if (sendingResult.IsSuccess != true)
                {
                    WorkContext.Form.Errors.Add(SecurityErrorDescriber.ErrorSendNotification(sendingResult.ErrorMessage));
                    return(View("customers/login", WorkContext));
                }

                WorkContext.Form = Form.FromObject(veryfyCodeViewModel);

                return(View("customers/verify_code", WorkContext));
            }

            if (loginResult.IsLockedOut)
            {
                return(View("lockedout", WorkContext));
            }

            if (loginResult is CustomSignInResult signInResult && signInResult.IsRejected)
            {
                WorkContext.Form.Errors.Add(SecurityErrorDescriber.AccountIsBlocked());
            }

            WorkContext.Form.Errors.Add(SecurityErrorDescriber.LoginFailed());

            return(View("customers/login", WorkContext));
        }