Authentication Filters in ASP.NET MVC 5
Filters are used to perform logic either before an action method is called or after an action method runs. Filters are custom classes that provide both a declarative and programmatic means to add pre-action and post-action behaviour to controller action methods.
Prior to ASP.NET MVC 5, there are 4 types of filters:
- Authorization filters (IAuthorizationFilter)
- Action filters (IActionFilter)
- Result filters (IResultFilter)
- Exception filters (IExceptionFilter)
Prior to ASP.NET MVC 5 we are using the [Authorization] attribute to enforce role-based security within the ASP.NET MVC applications. ASP.NET MVC 5 introduces the new Authentication filters (IAuthenticationFilter).
Authentication filters are a new kind of filter in ASP.NET MVC that run prior to authorization filters in the ASP.NET MVC pipeline and allow you to specify authentication logic per-action, per-controller, or globally for all controllers. Authentication filters process credentials in the request and provide a corresponding principal. Authentication filters can also add authentication challenges in response to unauthorized requests.
The reason for introducing authentication filters is to separate authentication from authorization (authentication first, then authorization):
- Authentication is for establishing a principal for current request
- Authorization is to verify whether or not the current principal is permitted to execute current request
We can use the IAuthenticationFilter (System.Web.Mvc.Filters) to create a custom authentication filter. Here is the definition of IAuthenticationFilter:
namespace System.Web.Mvc.Filters { public interface IAuthenticationFilter { void OnAuthentication(AuthenticationContext filterContext); void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext); } }
IAuthenticationFilter interface provides two methods:
- OnAuthentication(AuthenticationContext filterContext)
- This method is used to authenticates the request & it provides the context to use for authentication.
- OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
- This method adds an authentication challenge to the current ActionResult & it provides the context to use for the authentication challenge.
We can use authentication filters to allow users to authenticate to the application from various third-party vendors (facebook, linkedin, twitter etc…) or a custom authentication provider.
If look into real implementation details by comparing IAuthorizationFilter & IAuthenticationFilter, IAuthenticationFilter’s OnAuthentication(…) method has AuthenticationContext parameter which has Principal object.
When ControllerActionInvoker class InvokeAction() method is executed to Invoke an Action method, first it will iterate through the all Authentication filters OnAuthentication() methods. Then replace the original Principal object on the HttpContext in case if the Principal is changed by Authentication filters OnAuthentication() method.
protected virtual AuthenticationContext InvokeAuthenticationFilters(ControllerContext controllerContext, IList<IAuthenticationFilter> filters, ActionDescriptor actionDescriptor) { if (controllerContext == null) throw new ArgumentNullException("controllerContext"); IPrincipal user = controllerContext.HttpContext.User; AuthenticationContext filterContext = new AuthenticationContext(controllerContext, actionDescriptor, user); foreach (IAuthenticationFilter authenticationFilter in (IEnumerable<IAuthenticationFilter>) filters) { authenticationFilter.OnAuthentication(filterContext); if (filterContext.Result != null) break; } IPrincipal principal = filterContext.Principal; if (principal != user) { filterContext.HttpContext.User = principal; Thread.CurrentPrincipal = principal; } return filterContext; }
This is give us ability to modify the original Principal object using authentication filter’s. Here is the story with OnAuthenticationChallenge() method.
protected virtual AuthenticationChallengeContext InvokeAuthenticationFiltersChallenge(ControllerContext controllerContext, IList<IAuthenticationFilter> filters, ActionDescriptor actionDescriptor, ActionResult result) { AuthenticationChallengeContext filterContext = new AuthenticationChallengeContext(controllerContext, actionDescriptor, result); foreach (IAuthenticationFilter authenticationFilter in (IEnumerable<IAuthenticationFilter>) filters) authenticationFilter.OnAuthenticationChallenge(filterContext); return filterContext; }
Here is the end of authentication filter story, I don’t have solid use case to implement an authentication filter please do wait for sample implementation example in the next post.