0

I am implementing a collaborative web gallery, and I have a few roles for each user:

  1. Admin
  2. DeleteImage
  3. DeleteOwnImage
  4. etc..

For any controller-action, we can apply [Authorize] tag to them plus which roles we want to allow, right? It is fine for Admin/DeleteImage since these two are global; but my question is, like DeleteOwnImage is kind of contextual, in order to determine whether it is valid, we need:

  1. To know what image it is trying to delete (from request)
  2. Retrieve the owner of that image (from service or repository)
  3. Compare current user = that owner

Obviously [Authorize] is not enough to do so, but is it possible to do that on custom ActionFilters? Any hint?

2 Answers 2

4

Yes, this is possible with a custom action filter. You can extend from AuthorizeAttribute, the most basic implementation being something like:

public class OwnImageAuthorizeAttribute : AuthorizeAttribute {
    public string ImageIdKey { get; set; }

    protected override bool AuthorizeCore(HttpContextBase httpContext) {
    bool authorized = false;
    // Get the current user
    var currentUser = ...;
    // Get the image ID, whether it is in the route or querystring
    int imageId
    if(int.TryParse(httpContext.RouteData.Values(ImageIdKey), out imageId)) {
        // From querystring: httpContext.Request.Querystring[ImageIdKey]
        // Authorize the user
        authorized = YourMethodToCheckIfUserIsOwner(currentUser, imageId);
    }

    return authorized;
}

Then, decorate your method:

[OwnImageAuthorize(ImageIdKey = "imageId")]
public ActionResult MyAction() { }

You can find some more details here.

Sign up to request clarification or add additional context in comments.

2 Comments

Don't you think that this kind of method of authorization could get out of hand (read: lots of small classes which handle very specific issues) if you start doing this for every DB transaction which requires you to update something in the DB?
one thing I worried about is the Attribute itself is quite dependent on the input routedata. The "imageId" is named imageId in this action, but in other routing it may became "Id". But I think there's no way to get rid of this, right?
1

You can easily add something like this in an ActionFilter, Just add an action filter with OnActionExecuting implemented.

Although, depending on your DB schema this could be achieved on the DB level with your query. You could just delete when owner equals recieved recieved id. (I mean, inside the action method and not in the filter)

EDIT: If you're using some kind of IOC container for the repositories, you should look around for the new IOC features in MVC3 (if you're using MVC3) to inject dependencies into your action filters.

http://bradwilson.typepad.com/blog/2010/07/service-location-pt4-filters.html

EDIT2:

BTW, I myself don't really like doing too much business logic in ActionFilters, especially involving calls to the DB. Even more when it's something very specific that'll be used for one action.

1 Comment

also Ninject-mvc3 can do the injection. I think you are right, that's already stepped into business logic.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.