由問題引出
在ASP .NET MVC中,以友好的URL訪問資源是MVC吸引眼球的特色之一,但是隨之而來對於Authorize問題的處理變得令人令人頭痛。例如假設我們有一個獲取Book信息的Action,定義在BookController中:
public class BookController : Controller
{
// Release : code01, 2009/04/22
// Author : Anytao, http://www.anytao.com
public ActionResult Index(int id)
{
Book model = (new IBookService()).GetBook(id);
return View(model);
}
}
那麼,我們可以通過http://anytao.net/Book/index/1,來訪問id為1的Book(例如該書是《你必須知道的.NET》,哈哈,廣告嫌疑)。在沒有任何特別處理的情況下,對於該書的訪問是“不設防”的。任何用戶可以通過http://anytao.net/Book/index/1實現對《你必須知道的.NET》信息的訪問。那麼訪問的資源如果是http://anytao.net/Secret/index/1,顯然我的秘密無一例外的對外公開了。
言之此處,我們的問題已經明白無疑,那麼應該如何處理呢?我們可以很容易的想到通過以下的方式進行處理:
// Release : code02, 2009/04/22
// Author : Anytao, http://www.anytao.com
public ActionResult Index(int id)
{
if (new IAuthorizeService().IsBookAuthorized(id, User.Identity.Name))
{
Book model = (new IBookService()).GetBook(id);
return View(model);
}
else
{
return View("NotValid");
}
}
顯然,我通過IsBookAuthorized對GetBook服務的訪問有效性進行控制,通過User的Name在數據庫或者其他資源存儲進行查找, 然後根據IsBookAuthorized結果進行是否訪問的控制,顯然不合法的用戶將被導航到NotValid頁,提示你是非法用戶。
這種方式顯然是最容易想到的辦法,而且也廣泛存在於我們實際的應用中,例如NerdDinner范例中也是通過這種方式進行Authorize控制處理的,例如:
[Authorize]
public ActionResult Edit(int id) {
Dinner dinner = dinnerRepository.GetDinner(id);
if (!dinner.IsHostedBy(User.Identity.Name))
return View("InvalidOwner");
return View(new DinnerFormViewModel(dinner));
}
然而這種方式存在或多或少的問題,例如:
IsBookAuthorized將分散於不同的Action或者BLL層中,對於統一的Authorized管理帶來問題。
實際的Authorized執行已經滲透到Action或者Serivce內部,我們更期待在Action調用之前對此已經進行了處理。