我正在设计一个MVC 3应用程序,其中多个租户驻留在一个数据库中。
阻止用户在MVC中编辑/查看其他租户数据的最佳方法是什么? (即有人可以输入'/ People / Edit / 1'并编辑Id为1的人,无论他们是否属于租户数据)。
我知道我可以为每个控制器覆盖'OnActionExecuting(ActionExecutingContext filterContext)'但是,分别处理每个动作听起来很疯狂,取决于它是POST还是GET获取ID或OBJECT然后检查操作是允许的。
有更好的想法吗?
此外,我不想为每个租户创建不同的数据库或架构。
提前致谢。
答案 0 :(得分:1)
不是将id传递给控制器,而是为实体编写一个自定义模型绑定器,它将从数据库中获取它。例如,假设您有以下模型:
public class Person
{
public string Id { get; set; }
... some other properties
}
现在而不是:
[HttpPost]
public ActionResult Edit(string id)
{
...
}
写:
[HttpPost]
public ActionResult Edit(Person person)
{
...
}
然后为Person编写自定义模型绑定器:
public class PersonModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var id = bindingContext.ValueProvider.GetValue("id");
// check if an id was provided and if the user is authenticated
if (!controllerContext.HttpContext.User.Identity.IsAuthenticated || id == null)
{
throw new HttpException(403, "Forbidden");
}
var currentUser = controllerContext.HttpContext.User.Identity.Name;
// fetch the person from your repository given the id and belonging
// to the currently authenticated user
var person = _repository.GetPerson(id.AttemptedValue, currentUser);
if (person == null)
{
// no person found matching
throw new HttpException(403, "Forbidden");
}
return person;
}
}
您将在Application_Start
注册:
ModelBinders.Binders.Add(typeof(Person), new PersonModelBinder());
答案 1 :(得分:0)
原始回答
要快速解决问题,请使用guids而不是自动增加整数。然而,这只是推迟了这个问题。
您可以做的一件事就是角色您自己的授权attribuut http://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute.aspx或者您可以选择创建一个全局动作过滤器。 http://www.asp.net/mvc/tutorials/understanding-action-filters-cs
根据评论中的请求添加有关如何执行此操作的信息
public class MySuperFilter : ActionFilterAttribute
{
//Called by the MVC framework before the action method executes.
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
String user = filterContext.HttpContext.User.Identity.Name;
int id = int.Parse(filterContext.RouteData.GetRequiredString("Id"));
if (!IsValidUser(user,id))
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary {{ "Controller", "YourController" },
{ "Action", "YourAction" } });
}
base.OnActionExecuting(filterContext);
}
private bool IsValidUser(string user,int id)
{
//Check if the user has acces to the page
return true;
}
}
答案 2 :(得分:0)
这是一个非优雅的解决方案,但根据范围,它可能是最简单的。设计了一个类似的系统,对于多个租户数据的入口点相对较少,我们只是检查CurrentUser是被查询对象的所有者。我们的使用对象是具有所有者字段的公共基本接口,因此检查不会携带特定对象,而只是来自接口。如果存在不匹配,我们会抛出一个安全异常,并记录用户可能正在查询字符串,看看他们是否让我们的网站以多个生产网站的方式泄露数据。