MVC 4 Forms Authentication not working with [Authorize]

Carlos Landeras picture Carlos Landeras · May 21, 2013 · Viewed 24.3k times · Source

I'm learning MVC4 right now, and I am following the Pro ASP NET MVC4 4th edition book to create a Sports Store project.

I have always developed in webforms, and I am trying to figure out how the forms authentication is working in MVC4.

Here is what I have achieved:

Web.Config

<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880"/>  </authentication>

AccountController login Action:

[HttpPost]
        public ActionResult Login(LoginViewModel model, string returnUrl)
        {
            if (ModelState.IsValid)
            {
                if (authProvider.Authenticate(model.UserName, model.Password))
                {
                    return Redirect(returnUrl ?? Url.Action("Index", "Admin"));
                }
                else
                {
                    ModelState.AddModelError("", "Incorrect username or password");
                    return View();
                }
            }
            else
            {
                return View();
            }
        }

Auth Provider:

public bool Authenticate(string username, string password) {
            bool result = FormsAuthentication.Authenticate(username, password);
            if (result)
            {
                FormsAuthentication.SetAuthCookie(username, false);
            }

            return result;

        }

I am setting the AuthCookie and now I would like to know, how to protect other controllers and actions out of the AccountController

The application has a controller called AdminController, where you can edit products and the
product list in under the following {controller/action}

Admin/Index

So, If I am not missunderstanding the theory, if the user is not logging in the AccountController they should not be able to call actions with [Authorize] tag on declaration:

 public class AdminController : Controller
    {
        private IProductRepository repository;


        public AdminController(IProductRepository repo)
        {
            repository = repo;
        }

       [Authorize]
        public ActionResult Index()
        {

            return View(repository.Products);
        }
   }

The thing is I can call the Index action of the Admin Controller without any problem and without introducing the login.

I need some guidance to understand how this works. I have done some research and could not find anything, and the book is not covering this topic.

Thanks in advance.

EDIT: I closed Chrome Browser and worked without changing anything. I was working with tabs and I guess the cookie was active even stopping and starting debugging.

Answer

Darin Dimitrov picture Darin Dimitrov · May 21, 2013

If a controller action is decorated with the [Authorize] attribute (as is your Admin/Index action) you cannot invoke this action if you do not have a valid forms authentication cookie in the request.

Also in your Login action, upon successful authentication you should not return a view but you should redirect away, so that the cookie is properly set and available on subsequent requests.

Here's what should happen when a non-authenticated user attempts to access the protected Admin/Index action. The [Authorize] attribute will throw a 401 exception, which as you know from the classic WebForms will be intercepted by the Forms Authentication module and you will be redirected to the loginUrl configured in your web.config passing a ReturnUrl query string parameter the initially requested protected resource.

So you must have a Login action on the account controller that is not decorated with the [HttpPost] attribute and which should serve the view containing the sign-in view. The request will look like this:

/Account/Login?ReturnUrl=%2Fadmin%2Findex