AOP實踐--利用MVC5 Filter實現登錄狀態判斷


AOP有的翻譯“面向切面編程”,有的是“面向方面編程”。其實名字不重要,思想才是核心,mvc的Filter讓我們很
方便達到這種面向方面編程,就是在現有代碼的基礎上注入外部代碼,也就是所謂的面向方面編程,比如身份
驗證。

下面通過一個具體的例子來體驗一下MVC的AOP。
1、定義一AuthenAdminAttribute特性類

public class AuthenAdminAttribute : FilterAttribute, IAuthenticationFilter
{
	public void OnAuthentication(AuthenticationContext filterContext)
	{
	        //這個方法是在Action執行之前調用
		var user = filterContext.HttpContext.Session["AdminUser"];
		if (user == null)
		{
			//filterContext.HttpContext.Response.Redirect("/Account/Logon");
			var Url = new UrlHelper(filterContext.RequestContext);
			var url = Url.Action("Logon", "Account", new { area=""});
			filterContext.Result = new RedirectResult(url);
		}
	}
	public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
	{
		//這個方法是在Action執行之后調用
	}
}

是否登錄是通過Session鍵值為AdminUser的值是否為null判斷,如果為null也就是還沒有登錄或者過期了,就跳
轉到登錄頁面,即"/Account/Logon"。

注意:上面OnAuthentication是在最開始被調用的,也在ActionFilter方法之前。而OnAuthenticationChallenge
方法是在Action執行之后,返回視圖之前被調用。所以要把登錄驗證寫在方法OnAuthentication中。而且在里面
我們用到了設置filterContext.Result = new RedirectResult(url);而不是跳轉的形式,很關鍵的。MVC在執行
Filter時,如果我們手動用一個ActionResult對象指定了其Context對象的Result屬性的值,那么這個這個
ActionResult將作為這個請求的結果輸出,並且在這次請求管道中剩下的步驟將不再繼續執行。反之如果沒有
設置filterContext.Result的值,它會繼續執行接下來的步驟,甚至是Action方法,就算我們設置了跳轉。

2、定義登錄Controller

public class ManageController : Controller
{
 
        public ActionResult Logon()
        {
            return View();
        }
        [HttpPost]
        public ActionResult Logon(string username,string password)
        {
            if (username == "admin" && password == "admin")
            {
                Session["AdminUser"] = username;
                return RedirectToAction("Index",
                                        "Order", new { area = "Admin" });
            }
            else
                ViewBag.Error = "用戶名或密碼不正確!";
            return View();
        }
       
        public ActionResult LogOff()
        {
            if (Session["AdminUser"] != null)
            {
                Session["AdminUser"] = null;
            }
            return RedirectToAction("Logon");
        }
 }

Action名為Logon的方法就是里面就是登錄相關邏輯,這里的邏輯我為了簡單化,就直接把用戶名和密碼固定寫
死了。當然實際過程中你可以根據你自己的需要,比如結合數據庫表記錄來判斷用戶名密碼是否合法,如果合
法就相應的信息存在Session里面,當然你也可以存在Cookie里。

注意:這里登錄成功之后的存Session的key一定要和上面第一步的AuthenAdminAttribute用到的key一致。

3、設置需要登錄判斷的Controller或者Action
最后就是根據你的需要,看哪些Controller或者Action需要登錄才能訪問,只需要在前面加上我們在上面定義好
的特性類就可以了。

[AuthenAdmin]
public class CategoryController : Controller
{
  public ActionResult Index()
  {
   //此處省略具體邏輯代碼
   return View();
  }
}

上面是對整個Controller都要登錄驗證,就是這個Controller的所有Action必須要登錄才能訪問。那如果要針對單
獨的一個Action控制,其它不做要求呢?這也很好辦。代碼這樣寫就可以了。

public class CategoryController : Controller
{
  public ActionResult Index()
  {
   //此處省略具體邏輯代碼
   return View();
  }
  [AuthenAdmin] 
  public ActinResult List()
  {
     //此處省略具體邏輯代碼
    return View();
  }
}

這樣就是只有List這個Action需要登錄,Index就不用登錄就能訪問。
最后,說一下第一步為什么我要自己實現IAuthenticationFilter接口,而不直接繼承AuthorizeAttribute,比如這
樣寫

public class CustomAuthAttribute : AuthorizeAttribute {
	private bool localAllowed;
 
	public CustomAuthAttribute(bool allowedParam) {
		localAllowed = allowedParam;
	}
 
	protected override bool AuthorizeCore(HttpContextBase httpContext) {
		var user = httpContext.Session["AdminUser"];
		return user != null
	}
}

可以看到AuthorizeAttribute核心方法是AuthorizeCore返回值是一個bool類型,也就是只能判斷是否登錄過了,
這種情況如果你的系統采用Form驗證這個,確實是一個簡單可行的方案。如果要涉及到更加細微的權限控制或
者要把登錄信息存儲到Session或者其實地方就不太好辦了,因為ASP.NET的Form驗證是基於Cookie的。所以
我一般建議自己實現接口IAuthenticationFilter,這樣讓我們的系統更加靈活,更加容易擴展和控制。

這樣最后來看我們的業務邏輯代碼不會有身份驗證相關的代碼,登錄驗證和業務邏輯代碼完全隔離開了,業務邏
輯代碼變得簡潔了許多,這就是我理解的:你只需要針對一方面編程,也就是AOP提倡的面向方面編程。AOP
技術讓我們的軟件模塊之間的耦合性降低,大大的提高的我們軟件的可維護性和可復用性,AOP你值得擁有。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM