How to implement custom Authorize attribute for th

2020-01-27 00:46发布

问题:

so 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 wich 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 recieveing the PostEntry id as a route parameter but thats after the atribute and also attributes only accept constant parameters, looks like something very difficult, your answers are highly appreciated, Cheers!

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


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