利用Attribute Type打造一個類MVC的驗證

今天有個朋友詢問到C#的Attribute的使用方式與觀念,並且提到ASP.NET MVC裡面的一些神奇用法,例如為何Controller類別的方法上面冠上[Authorize]就會自動驗證了呢?例如下列程式碼:

public class ShitController : Controller
{
  [Authorize]
  public ActionResult Shits()
  {
    return View();
  }
}

向朋友稍微說明了一下Attribute的運行機制以及簡單的ASP.NET MVC架構後,朋友說是否可以在WebForm上面實現一次給他看?其實MVC底層有很多Reflection,讓你參數取得的途徑太爽,一般狀況下不太可能以範例的方式完全模擬,不過稍微弄出一點點味道倒是可以的。

建立報明牌網頁dataView.ashx

以下以泛型處理常式ASHX,搭配Attribute類別來進行範例,此網頁需要登入才能看的到,因此我們冠上[Authorize]屬性類別。

<%@ WebHandler Language="C#" Class="dataView" %>

[Authorize]
public class dataView : CheckMember, System.Web.IHttpHandler
{
  public void ProcessRequest (System.Web.HttpContext oContext)
  {
    System.Random oRnd = new System.Random();
    oContext.Response.Write($"本期最新明牌報號:{oRnd.Next(0, 100)}");
  }

  public bool IsReusable {get {return false;} }
}

建立Attribute類別

在這邊為了更清楚表達這個類別也是可以有多重的屬性設定的,因此故意實作多載,讓操作者可以在上面直接關閉驗證,但其實效果就等同於「沒打」[Authorize]這段文字。

public class AuthorizeAttribute : System.Attribute  //記得要繼承System.Attribute,因為它是一個屬性類別啊
{
  public AuthorizeAttribute()
  { bIsNeedAuth = true; }

  public AuthorizeAttribute(bool bTemp)
  { bIsNeedAuth = bTemp; }

  public bool bIsNeedAuth { get; set; }
}

建立CheckMember類別

但天底下最好會有這麼爽的事情,加上一個[Authorize]就會自動幫你把這網頁驗證?其實我們要靠後面這個CheckMember繼承類別幫我們在後面偷偷「讀取屬性並實作驗證」,最辛苦的就是這個類別啦!

using System.Reflection;
public class CheckMember
{
  public CheckMember()
  {
    var oAuthorize = this.GetType().GetCustomAttribute<AuthorizeAttribute>();
    //未設定認證屬性
    if (oAuthorize == null) { return; }
    //設定認證屬性,但屬性為false
    if (!oAuthorize.bIsNeedAuth) { return; }
    //協助認證傳遞過來的帳號密碼參數
    var oContext = System.Web.HttpContext.Current;
    string cAcc = oContext.Request.Form["cAcc"]?.ToString();
    string cPwd = oContext.Request.Form["cPwd"]?.ToString();
    //如果帳號密碼不對就踢走
    if (!(cAcc == "john" && cPwd == "1234"))
    {
      oContext.Response.Write("使用本服務需要登入正確的帳號密碼。");
      //攔截Context強制中斷
      oContext.Response.Flush();
      oContext.ApplicationInstance.CompleteRequest();
    }
  }
}

像不像三分樣,基本上的運作原理大概就是這樣,不過WebForm這個環境沒有MVC那樣爽,幫你把前端傳過來的參數包整理好丟給你,所以你看我們要自行攔截POST過來的帳號密碼自己處理嘍!

運行時期如果你的程式碼「沒有」加上[Authorize],或者是加上的程式碼是[Authorize(false)],那基本上就是可以看到明牌嘍!

如果「有」加上[Authorize],那麼你一定要POST正確的帳號密碼給dataView.ashx,才有可能會看到寶貴的明牌,例如下圖:

C# Attributes AttributeType SampleCode ASP.NET WebForms MVC Authorize Authorization