2012-11-06 47 views
3

我正在編寫一個MVC 3應用程序,用戶可以在其中登錄和管理其數據。我想阻止用戶查看或篡改其他用戶的數據。我的第一反應是,只是驗證訪問相關對象中的每個操作方法是這樣的:從MVC中的自定義授權屬性訪問操作方法參數3

public ActionResult ShowDetails(int objectId) 
{ 
    DetailObject detail = _repo.GetById(objectId); 
    if (detail.User.UserID != (Guid)Membership.GetUser().ProviderUserKey) 
    { 
     return RedirectToAction("LogOff", "Account"); 
    } 
} 

這工作得很好,但我認爲它可能是更好地把對象授權碼成一個自定義的授權來源於屬性AuthorizeAttribute,然後我可以將其應用於控制器。不幸的是,我一直無法找到一種方法來訪問我的自定義授權屬性中的操作方法參數。取而代之的是,我發現訪問傳入OBJECTID的唯一途徑是通過檢查httpContext.Request或filterContext.RequestContext.RouteData.Values:

public class MyAuthorizeAttribute : AuthorizeAttribute 
{ 
    private int _objectId = 0; 
    private IUnitOfWork _unitOfWork; 

    public MyAuthorizeAttribute(IUnitOfWork uow) 
    { 
     _unitOfWork = uow; 
    } 

    public override void OnAuthorization(AuthorizationContext filterContext) 
    { 
     int.TryParse((string) filterContext.RequestContext.RouteData.Values["id"], out _objectId); 
     base.OnAuthorization(filterContext); 
    } 

    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     int objectId = 0; 
     if (httpContext.Request.Params.AllKeys.Contains("id", StringComparer.InvariantCultureIgnoreCase)) 
     { 
      int.TryParse(httpContext.Request[idKey], out objectId); 
     } 

     if (objectId != 0) 
     { 
      if (!IsAuthorized(objectId, httpContext.User.Identity.Name)) 
      { 
       return false; 
      } 
     } 

     if (_objectId != 0) 
     { 
      if (!IsAuthorized(objectId, httpContext.User.Identity.Name)) 
      { 
       return false; 
      } 
     } 

     return base.AuthorizeCore(httpContext); 
    } 

    private bool IsAuthorized(int objectId, string userName) 
    { 
     DetailObject detail; 
     detail = _unitOfWork.ObjectRepository.GetById(objectId); 

     if (detail == null) 
     { 
      return false; 
     } 

     if (userName != detail.User.UserName) 
     { 
      return false; 
     } 

     return true; 
    } 
} 

我發現這種方法非常笨重。我真的不想在RouteData或Request對象中徘徊;由於模型綁定已經從RouteData和Request中提取了相關數據,因此能夠訪問操作方法參數將會更清晰。

我知道我可以訪問自定義動作過濾器(詳細here)的操作方法參數,但不應該將數據授權代碼放在授權過濾器中?我看到的授權過濾器的例子越多,我就越能得到他們只是想處理角色的印象。

我的主要問題是:如何從我的自定義授權屬性訪問操作方法參數?

+0

您是否找到了解決方案? – Ramesh

回答

3

回答你的主要問題:不,不幸的是AuthorizationContext不提供訪問操作參數。

首先,你可以使用ValueProvider不具備對付ID是否是路線的一部分或張貼查詢參數或HTTP,如下所示:

public override void OnAuthorization(AuthorizationContext filterContext) 
{ 
    string id = filterContext.Controller.ValueProvider.GetValue("id").AttemptedValue; 
    ... 
} 

這適用於簡單的數據類型和幾乎沒有開銷。然而,一旦你開始使用自定義模型粘合劑爲您的操作參數,你必須從ActionFilterAttribute繼承你的過濾器,以避免雙重結合:

[MyFilter] 
public ActionResult MyAction([ModelBinder(typeof(MyModelBinder))] MyModel model) 
{ 
    ... 
} 

public class MyFilterAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     var model = filterContext.ActionParameters["model"] as MyModel; 
     ... 
    } 
} 

雖然從AuthorizeAttribute語義繼承的授權目的聽起來更好,有沒有其他原因這樣做。此外,我發現使用ActionFilterAttribute更容易,因爲您只需重寫一個方法,而不是爲後續方法保留一個狀態。