简体   繁体   中英

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!

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();
}

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...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM