asp.net-mvc-3 - 从 MVC 3 中的自定义授权属性访问操作方法参数

标签 asp.net-mvc-3 security authorize-attribute

我正在编写一个 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 的自定义授权属性中可能会更好,然后我可以将其应用于 Controller 。不幸的是,我无法找到一种方法来从我的自定义 Authorize 属性中访问操作方法参数。相反,我发现访问传入 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 对象中四处寻找;能够访问操作方法参数会更清晰,因为模型绑定(bind)已经从 RouteData 和 Request 中提取了相关数据。

我知道我可以从自定义操作过滤器访问操作方法参数(详见 here ),但数据授权代码不应该放在授权过滤器中吗?我看到授权过滤器的示例越多,我就越觉得它们仅用于处理角色。

我的主要问题是:如何从我的自定义授权属性访问操作方法参数?

最佳答案

回答您的主要问题:不,很遗憾 AuthorizationContext 不提供对操作参数的访问。

首先,您可以使用 ValueProvider 来不必处理 id 是路由的一部分还是查询参数或发布的 HTTP,如下所示:

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

这适用于简单的数据类型并且引入的开销很小。然而,一旦您开始为您的操作参数使用自定义模型绑定(bind)器,您必须从 ActionFilterAttribute 继承您的过滤器以避免双重绑定(bind):

[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 更容易,因为您只需重写一个方法,无需为后续方法保留状态。

关于asp.net-mvc-3 - 从 MVC 3 中的自定义授权属性访问操作方法参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13257812/

相关文章:

iphone - 通过 WiFi 连接的设备与 Web 服务器建立长时间开放连接会出现哪些问题?

jquery - 返回部分 View 的 Controller 操作会在授权失败时插入登录页面

asp.net-mvc-3 - 如何正确使用 RedirectToAction

c# - MVC3 : Razor Validation Text: Make red without setting validation message to null

asp.net-mvc-3 - 自定义成员资格提供程序和统一依赖注入(inject)

asp.net-mvc - 系统或配置设置的外部控制

c# - HttpContext.Current.Request.Form 复选框

ASP.NET 应用程序通过防火墙表现出奇怪的行为

asp.net-mvc - ASP.NET MVC Beta Authorize 属性使我执行错误操作