Abstract: Explore the new IAuthenticationFilter in ASP.NET MVC 5 which allows you to customize authentication. Also learn about the CustomAuthentication attribute and how you can use to change the current principal and redirect un authenticated user to a login page.
Similar to AuthenticationContext, this method also creates an AuthenticationChallengeContext as shown here. Then it invokes the OnAuthenticationChallenge method per AuthenticationFilter.
ASP.NET MVC 5 has some great improvements around authentication. This includes new Authentication filters, new Authentication options and ASP.NET Identity Management.
In this article, we will take a look at the new authentication filters and how you can use these filters to make authentication decisions. At this stage, ASP.NET MVC does not provide any built-in authentication filter(s). However it provides you with the framework, so you can easily create your own custom authentication filters.
If you have used ASP.NET MVC before, you probably have used AuthorizationFilters. Authorization filters allow you to perform authorization tasks for an authenticated user. A good example is Role based authorization.
ASP.NET MVC 4 also introduced a built-in AllowAnonymous attribute. This attribute allows anonymous users to access certain Controllers/Actions. This way, you can protect the entire site by using this Authorize attribute and then use the AllowAnonymous attribute, to allow anonymous users to access certain Actions and Controllers. If you would like to read more on AllowAnonymous attribute, here’s a good articlehttp://blogs.msdn.com/b/rickandy/archive/2012/03/23/securing-your-asp-net-mvc-4-app-and-the-new-allowanonymous-attribute.aspx
New authentication filters run prior to authorization filters. It is also worth noting that these filters are the very first filters to run before any other filters get executed.
This article is published from the DotNetCurry .NET Magazine – A Free High Quality Digital Magazine for .NET professionals published once every two months. Subscribe to this eMagazine for Free and get access to hundreds of free tutorials from experts
So what is the real reason behind Authentication filters?
Prior to authentication filters, developers used the Authorization filters to drive some of the authentication tasks for the current request. It was convenient because the Authorization filters were executed prior to any other action filters. For example, before the request routes to action execution, we would use an Authorization filter to redirect an unauthenticated user to a login page. Another example would be to use the Authorization filter to set a new authentication principal, which is different from the application’s original principal in context.
Authentication related tasks can now be separated out to a new custom authentication filter and authorization related tasks can be performed using authorization filters. So it is basically about separating of concerns, while giving developers more flexibility to drive authentication using ASP.NET MVC infrastructure.
Authentication Filters as your standard Action Filters
As you would normally do with Action Filters, you can apply Authentication logic per Action, per Controller or Globally for all Controllers.
A practical example would be where your entire site runs on Forms based authentication using cookies, but you have a special requirement to support certain Controllers/Actions that should be transparent to a different authentication provider. This authentication provider would issue tokens along with the claim based authentication. Certain Controllers would have access to these claims principals. You can use a custom Authentication filter to set the new principal (i.e claims based), for the current request, just for the Controllers/Actions we need. The rest of the site will continue to work with the existing forms based authentication.
Creating a new custom Authentication Filter with ASP.NET MVC 5
We will first create a new ASP.NET MVC 5 application. Once you have installed Visual Studio 2013, navigate to File > New Project, under templates (C#/VB) select Web, and then select ASP.NET Web application. A dialogue box will pop up. Select “MVC” from the template. Then simply click on “Create Project”.
In order to create an Authentication filter, you must implement the IAuthenticationFilter. Below is the implementation of ASP.NET MVC’s IAuthenticationFilter.
public interface IAuthenticationFilter
{
void OnAuthentication(AuthenticationContext filterContext);
{
void OnAuthentication(AuthenticationContext filterContext);
void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext);
}
}
As I mentioned earlier, to be able to use these filters as your standard Action Filters, you also need to derive from ActionFilterAttribute. This allows you to decorate your Authentication filter in Controllers, Actions or use as a Global filter.
public class CustomAuthenticationAttribute : ActionFilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{
}
{
public void OnAuthentication(AuthenticationContext filterContext)
{
}
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
}
}
{
}
}
If you look at the above CustomAuthenticationAttribute, there are two interesting methods required to implement.
a. OnAuthentication
b. OnAuthenticationChallenge.
Let’s take a look at these two methods in detail.
OnAuthentication
During Action invocation, ASP.NET MVC invokes Authentication Filters by calling the following method:
AuthenticationContext authenticationContext = InvokeAuthenticationFilters(controllerContext, filterInfo.AuthenticationFilters, actionDescriptor);
This method creates an AuthenticationContext using the original principal, and executes each filter’s OnAuthentication method. Please see the following code:
AuthenticationContext context = new AuthenticationContext(controllerContext, actionDescriptor, originalPrincipal);
foreach (IAuthenticationFilter filter in filters)
{
filter.OnAuthentication(context);
}
{
filter.OnAuthentication(context);
}
AuthenticationContext provides you information for performing authentication. You can use this information to make authentication decisions based on the current context. For example, you may decide to modify the ActionResult to different result type based on the authentication context, or you may decide to change the current principal based on the authentication context etc.
If you change the user’s current principal to use a new custom principal, the ASP.NET MVC framework will set a new principal as shown here:
IPrincipal newPrincipal = context.Principal;
if (newPrincipal != originalPrincipal)
{
Contract.Assert(context.HttpContext != null);
context.HttpContext.User = newPrincipal;
Thread.CurrentPrincipal = newPrincipal;
}
{
Contract.Assert(context.HttpContext != null);
context.HttpContext.User = newPrincipal;
Thread.CurrentPrincipal = newPrincipal;
}
OnAuthenticationChallenge
OnAuthenticationChallenge method runs after the OnAuthentication method. You can useOnAuthenticationChallenge method to perform additional tasks on the request.
protected virtual AuthenticationChallengeContext InvokeAuthenticationFiltersChallenge(
ControllerContext controllerContext, IList filters,
ActionDescriptor actionDescriptor, ActionResult result)
ControllerContext controllerContext, IList
ActionDescriptor actionDescriptor, ActionResult result)
Similar to AuthenticationContext, this method also creates an AuthenticationChallengeContext as shown here. Then it invokes the OnAuthenticationChallenge method per AuthenticationFilter.
AuthenticationChallengeContext context = new AuthenticationChallengeContext(controllerContext,
actionDescriptor, result);
actionDescriptor, result);
foreach (IAuthenticationFilter filter in filters)
{
filter.OnAuthenticationChallenge(context);
}
{
filter.OnAuthenticationChallenge(context);
}
The key thing to remember is that OnAuthenticationChallenge does not necessarily run before every other Action Filter. It can run at various stages. For example, it can run after AuthorizationFilters or it can run after Action execution completed so on. Since this is at various stages, you now have the ability to change the action result based on the authentication.
As I mentioned earlier, you can use the OnAuthenticationChallenge method to modify the ActionResult.
filterContext.Result = new HttpUnauthorizedResult();
Implementing and configuring your custom Authentication Filter
We will use the CustomAuthenticationAttribute we just created and implement both OnAuthentication andOnAuthenticationChallenge methods. We will then configure it to execute only for HomeController’s Index action.
In OnAuthentication we set the current principal to a custom principal with some additional properties. InOnAuthenticationChallenge we check whether the user is authenticated or not and modify the ActionResult to anHttpUnAuthorizedResult.
CustomAuthenticationAttribute:
public class CustomAuthenticationAttribute : ActionFilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext) {
//For demo purpose only. In real life your custom principal might be retrieved via different source. i.e context/request etc.
filterContext.Principal = new MyCustomPrincipal(filterContext.HttpContext.User.Identity, new []{"Admin"}, "Red");
}
{
public void OnAuthentication(AuthenticationContext filterContext) {
//For demo purpose only. In real life your custom principal might be retrieved via different source. i.e context/request etc.
filterContext.Principal = new MyCustomPrincipal(filterContext.HttpContext.User.Identity, new []{"Admin"}, "Red");
}
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext) {
var color = ((MyCustomPrincipal) filterContext.HttpContext.User).HairColor;
var user = filterContext.HttpContext.User;
if (!user.Identity.IsAuthenticated)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
var color = ((MyCustomPrincipal) filterContext.HttpContext.User).HairColor;
var user = filterContext.HttpContext.User;
if (!user.Identity.IsAuthenticated)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
HomeController:
Here we execute the CustomAuthenticationAttribute only for HomeController’s Index Action. By configuring theCustomAuthenticationAttribute this way, we have the ability to control authentication just for Index action.
public class HomeController : Controller
{
[CustomAuthentication]
public ActionResult Index()
{
return View();
}
}
{
[CustomAuthentication]
public ActionResult Index()
{
return View();
}
}
OnAuthentication implementation will modify the current principal to use the new MyCustomPrincipal. During the Index action, we will use the new MyCustomPrincipal. Any other Action would use the original principal.
For example, accessing the MyCustomPrincipal from any other Action other than Index Action would not be possible. The following code would throw an exception:
public ActionResult About()
{
var color = ((MyCustomPrincipal)ControllerContext.HttpContext.User).HairColor;
{
var color = ((MyCustomPrincipal)ControllerContext.HttpContext.User).HairColor;
return View();
}
}
OnAuthenticationChallenge method sets the ActionResult as HttpUnAuthorizedResult for un- authenticated users. This causes user to redirect to a login page.
Additional Customizations
You probably know that the ASP.NET MVC Controller itself is also an ActionFilter.
public abstract class Controller : ControllerBase, IActionFilter, IAuthenticationFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IAsyncManagerContainer
{ }
{ }
With the introduction of IAuthenticationFilter, you can customize your authentication within the Controller as shown here:
public class HomeController : Controller
{
protected override void OnAuthentication(AuthenticationContext filterContext)
{
//custom authentication logic
}
{
protected override void OnAuthentication(AuthenticationContext filterContext)
{
//custom authentication logic
}
protected override void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
//custom authentication challenge logic
}
}
{
//custom authentication challenge logic
}
}
Summary
The new IAuthenticationFilter provides a great ability to customize authentication within an ASP.NET MVC 5 application. This provides a clear separation between authentication and authorization filters. OnAuthentication and OnAuthenticationChallenge methods provide greater extensibility points to customize authentication within ASP.NET MVC framework. We also looked at a sample usage of CustomAuthentication attribute and how you can use to change the current principal and redirect un authenticated user to a login page.
No comments:
Post a Comment