如何检查控制器中的记录所有权?

时间:2011-01-19 18:01:42

标签: asp.net-mvc

应用程序允许用户创建记录。为了我们的目的,让我们称这些记录为目标。

一个用户不应该看到其他用户创建的目标。

阻止UserA访问UserB目标的最佳方法是什么?

我可以这样做:

//using asp.net membership
Guid uId = (Guid)System.Web.Security.Membership.GetUser().ProviderUserKey;  
//goal records contain a foreign key to users, so I know who owns what
Goal theGoal = db.Goals.SingleOrDefault(g => g.GoalId == goalId 
                                          && g.UserId == uId);

if (null == theGoal)
{
  ViewData["error"] = "Can't find that goal.";
  return View("Error");
}
else
{
  return View(theGoal);
}

这很好用。问题是我在访问目标的每个操作中都有类似的代码。

是否有更可重用的方法来实现这一目标?

我想把它作为授权过滤器实现。该计划存在两个问题:

1)要求过滤器了解并使用DB 2)需要2个查询(过滤器中为1,操作中为另一个)而不是我现在的操作中的1个查询。

有什么更干嘛的方法来实现这个目标?

1 个答案:

答案 0 :(得分:2)

自定义模型绑定器是执行此操作的好地方:

public class GoalModelBinder : DefaultModelBinder
{
    private readonly IGoalRepository _repository;
    public GoalModelBinder(IGoalRepository repository)
    {
        _repository = repository;
    }

    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        // Here the default model binder does his job of binding stuff
        // like the goal id which you would use in the repository to check
        var goal = base.CreateModel(controllerContext, bindingContext, modelType) as Goal;
        var user = controllerContext.HttpContext.User;
        var theGoal = _repository.GetGoal(user, goal);
        if (theGoal == null)
        {
            throw new HttpException(403, "Not authorized");
        }
        // It's OK, we've checked that the Goal belongs to the user
        // => return it
        return theGoal;
    }
}

然后在Application_Start注册此模型绑定器:

// some implementation of your repo
var sqlRepo = new SqlGoalRepository();    
ModelBinders.Binders.Add(typeof(Goal), new GoalModelBinder(sqlRepo));

现在你的控制器动作变得不那么乱了:

[Authorize]
public ActionResult Edit(Goal goal)
{
    // if we get that far we are fine => we've got our goal
    // and we are sure that it belongs to the currently logged user
    return View(goal);
}