How to use custom Authorize attribute for roles as well as a specific user?

I have my Action Method

[Authorize(Roles="Admin")]
public ActionResult EditPosts(int id)
{
    return View();
}

In my case I need to authorize administrators so they can edit posts but (here comes the cool part), I also need to allow the creator of the post to be able to edit the post which is a normal user. So how can I filter out the user that created the post as well as the admins but leave the others unauthorized? I am receiving the PostEntry id as a route parameter but that’s after the attribute and also attributes only accept constant parameters, looks like something very difficult, your answers are highly appreciated, Cheers!

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

You could write a custom authorize attribute:

public class AuthorizeAdminOrOwnerOfPostAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var authorized = base.AuthorizeCore(httpContext);
        if (!authorized)
        {
            // The user is not authenticated
            return false;
        }

        var user = httpContext.User;
        if (user.IsInRole("Admin"))
        {
            // Administrator => let him in
            return true;
        }

        var rd = httpContext.Request.RequestContext.RouteData;
        var id = rd.Values["id"] as string;
        if (string.IsNullOrEmpty(id))
        {
            // No id was specified => we do not allow access
            return false;
        }

        return IsOwnerOfPost(user.Identity.Name, id);
    }

    private bool IsOwnerOfPost(string username, string postId)
    {
        // TODO: you know what to do here
        throw new NotImplementedException();
    }
}

and then decorate your controller action with it:

[AuthorizeAdminOrOwnerOfPost]
public ActionResult EditPosts(int id)
{
    return View();
}

Method 2

I understand that you have already accepted an answer, and this was posted a while back.. (btw:excellent answer for adding custom attributes), However I would point out the following:

If you are using this attribute once. On a Single method. This isn’t a good implementation. Instead you should have:

[Authorize]   // Just make sure they are auth'ed at all.
public ActionResult EditPosts(int id)
{
    Post SomePost = findPostByID (id);   // However you do it - single lookup of post

    if (!user.IsInRole("Admin") &&  !{IsOwnerOfPost(post)} )  Return Not Authorized

  ... Edit post code here
}

This has the advantages of:

  1. No additional class that someone will later wonder where it is used.
  2. No class that isn’t usable anywhere else (you don’t gain reuse with a custom attribute)
  3. Performance is better: Single fetch of the Post
  4. Way easier for someone to read/figure out how it works. No magic code to track down.
  5. And Years later, when HttpContextBase class doesn’t exist, or other parts of the tricks used to fetch the Id parameter are gone, the code still works…


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x