在ASP.NET MVC專案新增了開發偵錯專用的Controller,某些Action想限定從localhost存取,以免遭到誤用。逐一在Action加入檢查IP邏輯是種做法,但如此有點浪費ASP.NET MVC強大的擴充性,就好比提著子彈上膛的M16步槍上戰場,不扣板機卻拿槍托狂敲敵人的頭,不免有暴殄天物之憾。
以下是完整程式範例,為了增加應用彈性,我特別再抽出一層AllowedIpOnlyAttribute,宣告時傳入允許存取的IP清單;而LocalhostOnlyAttribute繼承AllowedIpOnlyAttribute,將允許IP寫死::1(IPv6)及127.0.0.1,成為AllowedIpOnlyAttribute的特例,做到限定本機存取。如此一魚兩吃,一次獲得兩種Filter,適用於不同情境。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MyWeb.Models
{
public class AllowedIpOnlyAttribute : FilterAttribute, IAuthorizationFilter
{
private string[] ipList = new string[] {};
//建構式接收以逗號或分號分隔的IP清單,限定存取來源
//TODO: 如要方便事後修改,可擴充成由config讀取IP清單,但會增加被破解風險
public AllowedIpOnlyAttribute(string allowedIps)
{
ipList = allowedIps.Split(',', ';');
}
#region IAuthorizationFilter Members
public void OnAuthorization(AuthorizationContext filterContext)
{
//實作OnAuthorization,當來源IP不在清單上,彈出錯誤
string clientIp = filterContext.HttpContext.Request.UserHostAddress;
if (!ipList.Contains(clientIp))
throw new ApplicationException("Disallowed Client IP!");
}
#endregion
}
//限定本機存取為AllowedIpOnlyAttribute的特殊情境,限定IP=::1或127.0.0.1
public class LocalhostOnlyAttribute : AllowedIpOnlyAttribute
{
public LocalhostOnlyAttribute()
: base("::1;127.0.0.1")
{
}
}
}
接著,見識Filter便利性的時刻來了,在Action加上AllowedIpOnly或LocalhostOnly,Action立刻變成限定特定IP或本機IP才能使用! 很方便吧?
[AllowedIpOnly("192.168.1.100")]
public ActionResult IpOnly()
{
return Content("IpOnly");
}
[LocalhostOnly]
public ActionResult LocalhostOnly()
{
return Content("LocalHostOnly");
}