基于请求的ASP条件编辑操作授权设计.. NET MVC应用



设计一个ASP。. Net MVC应用程序授权使用基于声明的模型。假设我们有一个叫做Product的对象。通常,有4种不同的操作-创建,编辑,删除和查看。授权是使用ClaimsAuthorize属性完成的。

[Authorize]
public class ProductController : Controller
{
     [ClaimsAuthorize("Product", "VIEW")]
     public List<Product> GetProducts()
     {
         // ....
     }
     [ClaimsAuthorize("Product", "CREATE")]
     public Product CreateNewProduct(Product product)
     {
         //....
     }
}

但是在我的情况下,我必须支持不同类型的编辑权限:

  1. 如果同一用户最初创建了该产品,则某些用户可以编辑该产品

  2. 如果产品属于特定的类别,某些用户可以编辑产品,并且该用户也可以访问同一类别

  3. 部分用户可以编辑所有产品(这是正常的产品编辑操作)

如何优雅地授权所有这些Edit操作(最好是如上所示的属性驱动),同时我希望将授权代码与正常的MVC控制器代码和业务逻辑分开。

[上面的代码示例在语法上不正确,我只是为了解释这个问题而编出来的]让我知道你的想法。

对于你问题的第一部分,基于索赔的授权,我已经在这个类似的问题中回答过了。这里我就不重复了

但是对于你的其他规则,比如产品只能由所有者编辑。你可以为每条规则编写单独的AuthorizeAttribute,并将它们应用到你的Actions上,下面是一个简单的例子:

using Microsoft.AspNet.Identity;
public class OwnerAuthorizeAttribute : AuthorizeAttribute
{
    private string _keyName;
    public bool IsPost { get; set; }
    public OwnerAuthorizeAttribute(string keyName)
    {
        _keyName = keyName;
    }
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        // imagine you have a service which could check owner of 
        // product based on userID and ProductID
        return httpContext.User.Identity.IsAuthenticated
            && this.ContainsKey
            && _productService.IsOwner(httpContext.User.Identity.GetUserId(),
                int.Parse(this.KeyValue.ToString()));
    }
    private bool ContainsKey
    {
        get
        {
            return IsPost
                ? HttpContext.Current.Request.Form.AllKeys.Contains(_keyName)
                // for simplicity I just check route data 
                // in real world you might need to check query string too 
                : ((MvcHandler)HttpContext.Current.Handler).RequestContext
                     .RouteData.Values.ContainsKey(_keyName);
        }
    }
    private object KeyValue
    {
        get
        {
            return IsPost
                ? HttpContext.Current.Request.Form[_keyName]
                // for simplicity I just check route data 
                // in real world you might need to check query string too 
                : ((MvcHandler)HttpContext.Current.Handler)
                    .RequestContext.RouteData.Values[_keyName];
        }
    }
}

你也可以在你的其他规则中重复同样的模式。

你可以简单地将你的自定义属性应用到你的动作中:

[OwnerAuthorize("id")]
public ActionResult Edit(int id)
{
    // your code
}
[HttpPost]
// double checking in post back too 
[OwnerAuthorize("id", IsPost = true)]
public ActionResult Edit(Product product)
{
    // your code
}

很明显,您可以将多个AuthorizeAttribute应用于您的操作。在这种情况下所有必须返回true

[ClaimsAuthorize("Product", "EDIT")]
[OwnerAuthorize("id")]
[YetOtherAuthorize]
public ActionResult MyFancyAction(int id)
{
}

最新更新