ASP.NET MVC ActionFilter: Custom Authorization
While the AuthorizeAttribute is great for forms authentication, there's always a number of ways to authorize a user. Today, I'll go over a template for a custom authorization ActionFilter.
A while back, I posted my top 5 favorite ASP.NET MVC Action Filters and enhancing your controllers with ActionFilters, but honestly, it doesn't matter which ActionFilter I pick. I just love the idea of ActionFilters. They are just so simple and powerful...and pretty darn cool!
For example, if you want to protect a certain section of your website, you place an [Authorize] attribute on an ActionResult method in your controller. If someone comes to your website and they try to hit that page and they aren't authorized, they are sent to the login page (Of course, you need to modify your web.config to point to the login page for this to work properly).
Last week, I received a question about how to create an authorization attribute for a website that uses something different than Forms Authentication.
So today, I will provide a simple template for building your own Authorize attribute. How you want to authenticate that user is up to you.
A 30-Line example
A quick note: ActionFilters use the HttpContext heavily to modify either redirects or modify specific output of HTML. From what I've heard about the new release of Visual Studio 2015, I'd like to know how HttpContext is handled inside of Core since the 30MB footprint of System.Web is removed from Core.
Do we still have an HttpContext in Core? If so, is it a stripped down version of HttpContext?
While I haven't played with Visual Studio 2015 yet, I've heard that it may be a good idea to hold off using .NET 4.6 for now.
Since I don't know if this example will work with Visual Studio 2015, stick with Visual Studio 2013 and this example should work fine.
public class RequiresAuthenticationAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext context) { var httpContext = context.HttpContext; if (!httpContext.User.Identity.IsAuthenticated) { if (httpContext.Request.Url != null) { var redirectOnSuccess = httpContext.Request.Url.AbsolutePath; var urlHelper = new UrlHelper(context.RequestContext); var url = urlHelper.LoginUrl(redirectOnSuccess); httpContext.Response.Redirect(url, true); } } base.OnActionExecuting(context); } }
There are two kinds of events for ActionFilters: OnActionExecuting (before the ActionResult is executed) and OnActionExecuted (after the ActionResult is executed). For our purposes, we will override the OnActionExecuting.
First, we check to see if the user is authenticated and if we have a Url.
If everything is OK, we grab the absolute Url from the request.
We also create a UrlHelper based on the RequestContext to get our Url for the Login page while passing in our "ReturnUrl."
NOTE: If you need a refresher on UrlHelpers, look over my post on ASP.NET MVC Url Helpers: Catalog Your Site.
Finally, we immediately redirect the user to the login page.
To use this ActionFilter, you apply it to either all of the ActionResults (page methods) in your controllers that you want protected or attach it to a controller to protect all of the methods in the controller.
[RequiresAuthentication] public ActionResult Posts(int? page, int? pageSize) { return View(_factory.GetViewModel<BlogController, PostAdminViewModel, PageData>(this, new PageData {PageNumber = page, PageSize = pageSize, TotalRecords = 0})); }
Conclusion
This template is completely open-ended and can be used for Windows Authentication, ActiveDirectory, Cookies, or HttpContext.Items. They can all be used for authenticating your users.
As you can see, ActionFilters are very versatile, small, and powerful.
What's your favorite ActionFilter? Is it an existing one or did you create one? Post your comments below.