如何为以下情况实现自定义Authorize属性?

时间:2012-07-15 17:02:23

标签: c# asp.net .net asp.net-mvc-3

所以我有我的行动方法

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

在我的情况下,我需要授权管理员,以便他们可以编辑帖子,但(这里是很酷的部分),我还需要允许帖子的创建者能够编辑普通用户的帖子。那么我怎样才能过滤掉创建帖子的用户以及管理员但是未经授权的其他人?我接受PostEntry id作为路由参数,但是在atribute之后,属性只接受常量参数,看起来非常困难,你的答案非常受欢迎,干杯!

2 个答案:

答案 0 :(得分:58)

您可以编写自定义授权属性:

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

然后用它装饰你的控制器动作:

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

答案 1 :(得分:5)

我了解您已经接受了一个答案,并且此答案已发布了一段时间。.(btw:添加自定义属性的出色答案),但是我要指出以下几点:

如果您一次使用此属性。在单一方法上。这不是一个好的实现。相反,您应该具有:

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

这具有以下优点:

  1. 没有其他类,以后有人会怀疑它在哪里使用。
  2. 没有在其他任何地方都无法使用的类(您无法通过自定义属性获得重用)
  3. 性能更好:只需提取帖子
  4. 使人更容易阅读/了解其工作方式。没有神奇的代码可以追踪。
  5. 几年后,当HttpContextBase类不存在,或者用于获取Id参数的技巧的其他部分都消失了时,代码仍然有效...