Authorize Action Filter in MVC

by Sachin Singh


Posted on Monday, 06 April 2020

Tags: Authorization in MVC Authentication and Authorization in MVC Authorize attribute MVC

In the previous article we have learnt about filters in MVC, we have also seen that all filters are used as attribute over a controller or Action or sometimes can be registered globally.

In this article we will uncover every detail of Authorize action filter. Authorize action filter is used as an attribute over a controller or action ,the purpose of using authorize attribute is to authenticate or authorize a user.

Authentication:-

Authentication means to check whether a user is a valid user meaning a registered user to your site or not. Usually in real time projects we use Authorize attribute to restrict the user if he is not an authenticated user. Meaning if a user is not logged in and try to access the Action which is marked as Authorize then we redirect them to the login page again. In order to make it work properly ,we implement Forms Authentication side by side.

Let's implement Forms Authentication and check how authorize attribute helps to achieve the desired outcome.

 Step 1.First add below lines to your webconfig file under System.Web tag to enable Forms Authentication.


    <authentication mode="Forms">
    <forms loginurl="~/Home/Login">
    </forms>
   </authentication>

Note:-loginurl is the path to your login action method, meaning if anyone tries to access an Action which is marked as Authorize then he will be redirected to the Login Page if he is not already logged in.

Step 2:- create two action methods one which returns a Login view and second which validates the user by comparing username and password provided by the user and the corresponding values from database ,for simplicity I have used the hard coded value.


       [HttpGet]
        public ActionResult Login(string ReturnUrl)
        {
            ViewBag.ReturnUrl = ReturnUrl;
            return View();
        }
        [HttpPost]
        public ActionResult Login(string UserName, string Password, bool RememberMe, string 
       ReturnUrl)
        {

            if (UserName == "sachin" & Password == "sachin@7777")
            {
                FormsAuthentication.SetAuthCookie(UserName, RememberMe);
                return Redirect(ReturnUrl);

            }

            return View("Login");
        }

Note 1:- Here Return URL is the URL of the resource, which the user tried to access but as he was not logged in he has been redirected to the login page. So after login, he will again redirect to the page, he wanted to access before logging in.

Note 2:- SetAuthCookie is a static method of FormsAuthentication class, which creates a cookie on the user browser with the name specified as the first parameter and RememberMe is a boolean value which signifies whether the user wants it to persist in his browser or not.


        @{
    ViewBag.Title = "Login";
      }
 <h2>Login</h2>
 <form action="/Home/Login" method="post">
    User Name:@Html.TextBox("UserName")
    Password :@Html.Password("Password")
    Remember Me:@Html.CheckBox("RememberMe")
   @Html.Hidden("ReturnUrl", new { @value = ViewBag.ReturnUrl})
  
    <button type="submit">Login</button>
    </form>

Step 3:- Mark any Method which you think needs validation with Authorize attribute.


          [Authorize]
          public ActionResult Post()
          {
              return View();
          }

Now run the application and try to access the above method, you will be redirected to the Login page. After login, you will be automatically redirected to the Post Action method.

Authorization:-

Authorization means whether a user has rights to access the resource or not. Sometimes a user might be a registered user and can be currently logged in but it doesn't make any sense to give him Admin rights. So if any logged-in user tries to access the admin page you will restrict him to access any such resource.

Step 1:-For authorization we use second overloaded version of Authorize attribute to specify the role. We can even specify multiple roles as comma-separated values. If a user is authenticated and in a role to access the resource then only he can access the resource.


         [Authorize(Roles="Admin,Editor")]
          public ActionResult Post()
          {
              return View();
          }

Here only users which are in role of Admin or Editor can access the Post Action Method.

Step 2:- Previously we have created a cookie having two parameter Name and RememberMe .The first parameter signifies the name of the cookie and second parameter signifies whether it is a persistant cookie or not.

But now the requirement has changed ,now we also have to check the role ,so first we have to insert the role in cookie .But cookie doesn't accept multiple parameters so we use FormsAuthentication ticket ,and add the role then insert this ticket into cookie. So, modify your Login method like below.


         [HttpPost]
        public ActionResult Login(string UserName, string Password, bool RememberMe, string ReturnUrl)
        {
            if (UserName == "sachin" & Password == "sachin@7777")
            {
                string roles="Admin,Editor"; //must be  comma separated.
                FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, UserName, System.DateTime.Now, 
               DateTime.Now.AddHours(24), RememberMe, roles);
                var EncryptCookie = FormsAuthentication.Encrypt(ticket);
                HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, EncryptCookie);
                HttpContext.Response.Cookies.Add(cookie);
            
                return Redirect(ReturnUrl);
            }
            return View("Login");
        }

• Let's understand the above code, first, we have created roles as a string with comma-separated value. I have used hardcoded value, you can retrieve user roles from the database.
• Now we created Forms Authentication ticket by specifying version as 1, name as the username, created on as current date, expiry as 24 hours, Is persistent as RememberMe, Userdata as roles.
• Then we have Encrypted the ticket.
• Created a cookie with the name as the ticket name and inserted the encrypted ticket into it.
• Now in the response object we have added the cookie.

HttpContext:-

It becomes important to understand what is HttpContext. HttpContext can be considered as a container ,which contains the request object and response object. Whenever an http request is initiated an HttpContext object is created by IIS .

Step 3:- Now we added the cookie which contains the ticket and ticket actually contains the role.But our work is not yet completed the Authorize attribute fetches roles from HttpContext object.So we will have to create a generic principal with roles into it in the Application_AuthenticateRequest event in global.asax .


         protected void Application_AuthenticateRequest(object sender,EventArgs e)
        {
            var authcookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
            if(authcookie!=null){
                FormsAuthenticationTicket authticket = FormsAuthentication.Decrypt(authcookie.Value);
                if(authticket!=null&!authticket.Expired){
                    var roles = authticket.UserData.Split();
                    HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(new FormsIdentity(authticket), roles);
                }
            }
        }

Now run the application and it will work as expected.