要允许用户和网站管理员在我的应用程序中查看/添加/编辑/删除数据,我决定使用此路线:
routes.MapRoute("ClientRoute",
"{account}/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" });
会产生如下路线:mvcapp.net/1234/contact/add。
为了让用户{除了管理员}访问其他客户端的数据,我在控制器操作中添加了以下代码。
...
var model = repos.GetSomeData();
if (User.IsInRole("Admin") == false) {
if (account == Profile["Client"])
return View(model);
else
return View("WrongClient");
}
...
这样做的最佳方式是什么?
我想解决的问题
public class BaseController : Controller {
protected override OnActionExecuting(ActionExecutingContect filterContext) {
if (filterContext.RouteData.Values["account"] != null) {
string client = filterContext.RouteData.Values["account"].ToString();
if (User.IsInRole("admin") == false) {
if (Profile.Clients.Contains(account) == false)
filterContext.Result = new ViewResult() {ViewName = "WrongClient"};
}
}
}
}
答案 0 :(得分:1)
您可以编写存储库方法,以便它们仅返回相应帐号的客户端数据。只需将帐号传递给存储库方法即可。
如果您担心将用户信息传递到存储库方法(正如Jabe在下面的评论中讨论的那样),那么您可以从存储库返回IQueryable,并对其运行Linq查询以进行安全修整。
答案 1 :(得分:0)
对于这个具体的例子,Azam Sharp在他的blog上有一个可能的解决方案。我差不多在五分钟前偶然发现了这篇文章。希望它有所帮助!
答案 2 :(得分:0)
考虑到您已经从个人资料中获得了这些信息,是否真的有必要让客户成为该路线的一部分?
至于处理它的存储库级别(如上所述) - 这可能会有点棘手,因为可能会阻止访问某些业务流程内部所需的数据以及不让用户访问它。当然,您可以创建单独的筛选/未筛选方法来处理此问题。此外,这可能是不允许混合客户数据的方式。
在我们的应用程序中,大部分时间只是添加/插入/删除的顶级项目需要以某种方式限制访问。它也只是一组有限的数据需要以这种方式受到限制,因此我通常会编写代码,如果违反该项的访问规则,则会在控制器中抛出某种异常。
如果您的应用规则非常相似,则可以通过多种方式避免重复代码。我们都会想到一个自定义的ActionFilter或自定义Controller基类。如果数据库中的每一行都有一个客户端ID或一些此类方案,则另一个选项是让您的域对象各自实现一个暴露此ID的接口。然后,您可以编写可重用的代码(mixin风格的扩展方法等),使用此接口作为应用各种安全规则的基础。
答案 3 :(得分:0)
我不确定Profile [“AccountNumber”]正在做什么(或者Profile来自哪里),但假设您可以随时创建该对象(或者如果已经创建了该对象);
您可以执行以下操作(将其放在您的控制器中):
protected override void ExecuteCore()
{
var model = repos.GetSomeData(int.Parse(base.RouteData.Values["client"])));
if (User.IsInRole("Admin") == false && Profile["AccountNumber"].ToString() != model.AccountNumber)
{
ViewData["Error"] = "You can't access this page";
View("WrongClient").ExecuteResult(ControllerContext);
}
else
base.ExecuteCore();
}
您可以将它放在所需的所有控制器中,或让控制器继承实现此功能的基本控制器类。