Introduction
Asp.Net MVC has been there in the market for more than a decade now and it is still the preferred choice of developing web applications with .NET Framework. There are lots of applications running in Asp.Net MVC in production. Although there has been a demand of migrating the .NET Framework to AspNetCore it is always better to understand how the technology got evolved into what it is now.
In this post we will understand the process of doing authentication and authorization in asp.net mvc application. We would be looking into FormsAuthentication specifically.
In our previous post we discussed the basics of What is Authentication and Authorization and How authentication and authorization works in asp.net particularly in Asp.Net WebForms Application.
You can refer to my previous post from the link below.
Understanding Authentication and Authorization in Asp.Net WebForms
Authentication and Authorization
As we already know from our previous post that Authentication answers the question Who the User is ? and Authorization answers the questions What the User has access to ?
Authentication and Authorization is needed to keep our web application secure and thus it is very important to know this process in depth.
Well, Authentication works the same way in MVC as it works in the Asp.Net WebForms. The below mentioned steps holds true in MVC as well.
- Specifying the Authentication Mode
- Validating the credentials
- Generating the Authentication Cookie
- Setting the value of the HttpContext.User property
- Using the HttpContext.User property for Authorization
If you want want to know about these steps further click here to go to my previous post.
Now we will specifically focus on things which are different in MVC.
[Authorize] Attribute
[Authorize] attribute is an attribute that can be placed on top of a controller or an action method.
If this attribute is placed on top of controller all the action methods defined inside the controller
has authorization enabled by default.
This means that user not having the required access level would be restricted and would be redirected
to the referrer or login url as specified.
Let us look into the code of the [Authorize] attribute to undertsand it better. We will not go through the entire class but we will look into the two most important methods in the implementation.
public virtual void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (OutputCacheAttribute.IsChildActionCacheActive(filterContext))
{
throw new InvalidOperationException(MvcResources.AuthorizeAttribute_CannotUseWithinChildActionCache);
}
if (!filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true) && !filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), inherit: true))
{
if (AuthorizeCore(filterContext.HttpContext))
{
HttpCachePolicyBase cache = filterContext.HttpContext.Response.Cache;
cache.SetProxyMaxAge(new TimeSpan(0L));
cache.AddValidationCallback(CacheValidateHandler, null);
}
else
{
HandleUnauthorizedRequest(filterContext);
}
}
}
All that is happening in the method is that in the filterContext if AllowAnonymous attribute is not defined then AuthorizeCore method would get called otherwise the otherwise the method execution would get skipped.
This implementation is there for a reason. Let us say you have a controller which has the Authorize attribute applied. So by default all the action methods can be executed by Authorized Users only. But if we want to exclude some of the methods from Authorization we need to provide the AllowAnonymous attribute on the action method that needs no authorization.
Let know now go through the AuthorizeCore method and look into the implementation.
protected virtual bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
IPrincipal user = httpContext.User;
if (!user.Identity.IsAuthenticated)
{
return false;
}
if (_usersSplit.Length != 0 && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
{
return false;
}
if (_rolesSplit.Length != 0 && !_rolesSplit.Any(user.IsInRole))
{
return false;
}
return true;
}
This method first of all checks for the User Identity present in the HttpContext. This method
does not care about anything but the Identity of the User in first place.
I have seen most of the people have a wrong impression that the Authorize attribute validates the
credentials and generates the FormsAuthenticationCookie.
The FormsAuthenticationCookie is generated by the application developer or the Asp.Net Identity
Framework after validating the credentials.
When the FormsAuthenticationCookie is sent to the server the FormsAuthenticationModule validates the
Cookie and sets the User Identity in the HttpContext.
In a way we can tell that Authorize attribute checks for Authentication as the first step and then processes the logic further.
In the second step the authorized user names mentioned in the Authorize attribute is validated with the user name in the Identity. If the user in the identity is one of the users mentioned in the attribute the execution continues further.
In the third step the authorized role names mentioned in the Authorize attribute is validated with the role namees in the Identity. If the role in the Identity is one of the roles mentioned in the attribute the execution continues further and the code in the action method is executed.
If any one of the above mentioned checks fails the further execution is terminated and an Unauthorized response if sent back.
Conclusion
In this post we discussed the different processes involved in authenticating a user in a Asp.Net Mvc application.
The basic steps involved is the same as that in WebForms Application.
The Authorize attribute plays an important role in validating the
- If the User is Authenticated
- If the User Name is Authorized
- IF the User Role is Authorized
I beleive that learning by going through the source code gives us a clear cut idea of what is
happening behind the scene.
The source code of the Authorize attribute clearly explains all it does.
Exploring ServiceProvider in .NET
Exploring ServiceDescriptor in .NET
Exploring ServiceCollection in .NET
Authentication and Authorization in AspNetCore
Authentication and Authorization in Asp.Net WebApi
Understanding Authentication and Authorization in Asp.Net WebForms
Exploring AddControllers() method in AspNetCore (.NET 7)
Understanding CreateBuilder() method in AspNetCore (.NET 7)
Setup and debug microsoft aspnetcore source code