Claims-based authorization design for a conditional edit operation in an ASP.NET MVC application

Develop authorization of an ASP.Net MVC application using a requirements-based model. Let's say we have an object called Product. As a rule, there are 4 different actions - creating, editing, deleting and viewing. Authorization is performed using the ClaimsAuthorize attribute.

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

But in my case, I have to support different types of EDIT rights:

  • Some users may edit the product if the same user created the product.

  • Some users can edit the product if the Product belongs to a certain category and the user also has access to the same category.

  • Some users can edit all products (this is a common product editing operation)

How do you elegantly authorize all these editing operations (preferably an attribute, as shown above), and at the same time I want to keep the authorization code separate from the normal controller code and the MVC business logic.

[Above the sample code is not syntactically correct, I just did it to explain this issue] Let me know your thoughts.

+2
asp.net-mvc claims-based-identity
Aug 06 '15 at 3:42 on
source share
1 answer

For the first part of your question, authorization based on a claim, I already answered this question to this similar question . And I'm not going to repeat here.

But for your other rules, such as products that are only editable by the owner. You can write a separate AuthorizeAttribute for each rule and apply them in your actions, considering this as a simple example:

 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]; } } } 

You can repeat the same pattern with different rules.

And you can just apply your custom attributes to your actions:

 [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 } 

Obviously, you can apply more than one AuthorizeAttribute to your actions. In this case, all of them should return true .

 [ClaimsAuthorize("Product", "EDIT")] [OwnerAuthorize("id")] [YetOtherAuthorize] public ActionResult MyFancyAction(int id) { } 
+4
Aug 6 '15 at 8:54
source share



All Articles