Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC Redirection in OnAuthorization causes authorization to fail

I'm trying to redirect the user to a different action if their email address has not been validated. The thing is, I don't want them to be logged out, I just want to redirect them. When I do this in OnAuthorization for the controller, it redirects as expected, but the user is not authenticated. I'm not sure why this is. My code looks like this:

    protected override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);

        //_applicationService.CurrentUser is populated correctly at this point
        // from Controller.User
        if (_applicationService.CurrentUser != null)
        {
            if (_applicationService.CurrentUser.EmailVerified != true)
            {
                var url = new UrlHelper(filterContext.RequestContext);
                var verifyEmailUrl = url.Action("EmailVerificationRequired", "Account", null);
                filterContext.Result = new RedirectResult(verifyEmailUrl);
            }
        }

    }

Note: I've removed unnecessary code to make it clearer. _applicationService.CurrentUser is populated with the current user - and the user has been authenticated correctly when it gets to that point. But after the redirect the user is no longer authenticated.

How can I achieve this redirect without affecting the built in user authorization?

I've tried putting my code into OnActionExecuting, and I've also tried implementing it in a custom ActionFilterAttribute as well, but wherever I put this redirect in it prevents the 'User' (ie: System.Security.Principal.IPrincipal Controller.User) from getting authenticated.

What am I missing here? Hope this makes sense. Any help much appreciated.

In response to Darin's request for my login action:

    [HttpPost]
    [AllowAnonymous]
    public ActionResult Login(LoginViewModel model, string returnUrl)
    {
        string errorMessage = "The username or password is incorrect";

        if (ModelState.IsValid)
        {
            if (_contextExecutor.ExecuteContextForModel<LoginContextModel, bool>(new LoginContextModel(){                    
              LoginViewModel = model  
            }))
            {
                ViewBag.CurrentUser = _applicationService.CurrentUser;
                _formsAuthenticationService.SetAuthCookie(model.LoginEmailAddress, model.RememberMe);

                if (_applicationService.IsLocalUrl(returnUrl))
                {
                    return Redirect(returnUrl);
                }

                return RedirectToAction("Index", "Home").Success("Thank you for logging in.");
            }
            else
            {
                errorMessage = "Email address not found or invalid password.";
            }
        }

        return View(model).Error(errorMessage);
    }
like image 244
soupy1976 Avatar asked Oct 22 '22 09:10

soupy1976


1 Answers

Okay, I've now found where I was going wrong. The problem was that I was being a bit of a goon and I didn't fully understand what was happening when I was doing:

filterContext.Result = new RedirectResult(verifyEmailUrl);

I didn't realise that I am actually starting a new request with this, I mistakenly thought that I was just redirecting to another action. It seems obvious now that this will be a new request.

So, the problem was that my EmailVerificationRequired action was not authorizing the user, and thus when it got to this action the current user was null. So the fix was add the authorization to that action and now it's all fine.

Thanks for your help guys.

like image 184
soupy1976 Avatar answered Nov 02 '22 23:11

soupy1976