ASP.NET MVC (CTP3/RC 時期) 尚無官方授權框架。本文探討如何復用 ASP.NET Forms 驗證機制,透過自訂 ActionFilterAttribute 實現基於角色的 Controller/Action 級權限控制,並比較繼承 BaseController 重寫虛擬方法的替代方案。
web.config `public interface IActionFilter
{
void OnActionExecuting(ActionExecutingContext filterContext);
void OnActionExecuted(ActionExecutedContext filterContext);
void OnResultExecuting(ResultExecutingContext filterContext);
void OnResultExecuted(ResultExecutedContext filterContext);
}
public abstract class ActionFilterAttribute : Attribute, IActionFilter { ... }
兩種套用方式:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class RequiresAuthenticationAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
var redirectOnSuccess = filterContext.HttpContext.Request.Url.AbsolutePath;
var redirectUrl = $"?ReturnUrl={redirectOnSuccess}";
var loginUrl = FormsAuthentication.LoginUrl + redirectUrl;
filterContext.HttpContext.Response.Redirect(loginUrl, true);
}
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class RequiresRoleAttribute : ActionFilterAttribute
{
public string RoleToCheckFor { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (string.IsNullOrEmpty(RoleToCheckFor))
throw new InvalidOperationException("No Role Specified");
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
var redirectOnSuccess = filterContext.HttpContext.Request.Url.AbsolutePath;
var loginUrl = FormsAuthentication.LoginUrl + $"?ReturnUrl={redirectOnSuccess}";
filterContext.HttpContext.Response.Redirect(loginUrl, true);
return;
}
if (!filterContext.HttpContext.User.IsInRole(RoleToCheckFor))
throw new UnauthorizedAccessException("You are not authorized to view this page");
}
}
[RequiresAuthentication]
public class AdminController : Controller
{
[RequiresRole("SuperAdmin")]
public ActionResult UserManagement() { ... }
[RequiresRole("ContentEditor")]
public ActionResult ArticleEdit(int id) { ... }
}
| 維度 | ActionFilter Attribute | BaseController 重寫 |
|---|---|---|
| 套用彈性 | 類別/方法級,可多重疊加 | 僅整個 Controller 統一策略 |
| 程式碼複用 | 高,跨專案可攜 | 低,需繼承特定基底 |
| 效能 | 屬性反射略慢 (微乎其微) | 虛擬方法呼叫最快 |
| 測試友善 | 易 Mock filterContext | 需建立 Controller 實例 |