Restrict Access to an MVC Action or Controller by IP Address using a Custom Action Filter

Scenario: You want to lock down access to a particular action or entire controller in your MVC application via the users IP address.  This can be particularly useful if you would like to restrict the Admin portion of your website to just your company’s IP address range.

There are several ways to accomplish this task. IIS allows you to restrict by IP Address but what if you want to do it programmatically…

Pseudo-code:

  1. Get users IP address
  2. Get list of valid IP addresses
  3. If users IP address is in the list of valid IP addresses, then display the secure page, else redirect the user to some other page.

Working within the context of ASP.NET MVC, putting this logic into a custom action filter would provide us application-wide access to this feature, making re-use as easy as decorating a particular action or entire controller with a single attribute.

Assuming you already have a working MVC application, create a new class that will hold the logic for your custom action filter. I like to put my custom action filters in a folder named Filters. For this example, I will create a new class named AuthorizeIPAddress.cs in my Filters folder and the code will look like this:

using System; 
using System.Web; 
using System.Web.Mvc; 
using System.Configuration;

namespace YourMVCApplication.Filters 
{ 
    /// <summary> 
    /// Only allows authorized IP addresses access. 
    /// </summary> 
    public class AuthorizeIPAddressAttribute : ActionFilterAttribute 
    { 
        public override void OnActionExecuting(ActionExecutingContext filterContext) 
        { 
            //Get users IP Address 
            string ipAddress = HttpContext.Current.Request.UserHostAddress;

            if (!IsIpAddressValid(ipAddress.Trim())) 
            { 
                //Send back a HTTP Status code of 403 Forbidden  
                filterContext.Result = new HttpStatusCodeResult(403);
            }

            base.OnActionExecuting(filterContext); 
        } 
        
        /// <summary> 
        /// Compares an IP address to list of valid IP addresses attempting to 
        /// find a match 
        /// </summary> 
        /// <param name="ipAddress">String representation of a valid IP Address</param> 
        /// <returns></returns> 
        public static bool IsIpAddressValid(string ipAddress) 
        { 
            //Split the users IP address into it's 4 octets (Assumes IPv4) 
            string[] incomingOctets = ipAddress.Trim().Split(new char[] { '.' });

            //Get the valid IP addresses from the web.config 
            string addresses = 
              Convert.ToString(ConfigurationManager.AppSettings["AuthorizeIPAddresses"]);

            //Store each valid IP address in a string array 
            string[] validIpAddresses = addresses.Trim().Split(new char[] { ',' });

            //Iterate through each valid IP address 
            foreach (var validIpAddress in validIpAddresses) 
            { 
                //Return true if valid IP address matches the users 
                if (validIpAddress.Trim() == ipAddress) 
                { 
                    return true; 
                }

                //Split the valid IP address into it's 4 octets 
                string[] validOctets = validIpAddress.Trim().Split(new char[] { '.' });

                bool matches = true;

                //Iterate through each octet 
                for (int index = 0; index < validOctets.Length; index++) 
                { 
                    //Skip if octet is an asterisk indicating an entire 
                    //subnet range is valid 
                    if (validOctets[index] != "*") 
                    { 
                        if (validOctets[index] != incomingOctets[index]) 
                        { 
                            matches = false; 
                            break; //Break out of loop 
                        } 
                    } 
                }

                if (matches) 
                { 
                    return true; 
                } 
            }

            //Found no matches 
            return false; 
        } 
    } 
}

And here is the code to put in your Web.config file in the appSettings section:


<appsettings> 
    
    <!-- IP addresses allowed to view IP Address Restricted portions of the website. 
         An asterisk indicates an entire subnet is valid. --> 
      <add value="::1, 127.0.0.1, 10.0.*.*, 79.88.44.33" key="AuthorizeIPAddresses" />

</appsettings>

Of course you could easily save and retrieve this information from a database or XML file if you choose.

And in your Controller, to implement this logic, simply place the following attribute above your controller or a particular action:


[AuthorizeIPAddress]

Example usage at the action level:


[AuthorizeIPAddress] 
public ActionResult AdministratorLogin() 
{ 
    return View(); 
}

Example usage at the controller level which will cause this logic to run on every action within the controller:


[AuthorizeIPAddress] 
public class AdministratorController : BaseController 
{ 
    ... 
}


The code should be self explanatory but I’ve added comments as well. There are many different ways to compare the users IP address to a list of valid IP addresses. My implementation is only so complex because it will also handle entire subnet ranges and not just a list of valid IP addresses by checking for the existence of an asterisk.