2012-11-06 113 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更容易,因为您只需重写一个方法,而不是为后续方法保留一个状态。