2009-11-09 65 views
0

为了让用户和网站管理员对我的申请,我决定这条航线上查看/添加/编辑/删除数据:减少重复的代码在控制器动作

routes.MapRoute("ClientRoute", 
     "{account}/{controller}/{action}/{id}", 
     new { controller = "Home", action = "Index", id = "" }); 

导致路线,如:mvcapp.net/ 1234 /接触/添加。

为了让用户{管理员除外}访问其他客户端的数据,我在控制器操作中添加了以下代码。

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

我不确定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(); 

} 

你可以把这个在你需要的所有控制器,或者控制器继承实现此功能的控制器基类。如果你是管理员,需要访问特定用户的信息(假设我想使用的用户创建了同样的观点)http://forums.asp.net/t/1382514.aspx

+0

HttpContext.Profile – 2009-11-09 19:48:59

+0

在这种情况下,我建议只检查“客户端”是否与用户的id相匹配(假设您使用clientid作为User.Identity.Name) – Omar 2009-11-09 23:03:08

+0

Paul Balmire的回复(第5或第6条)让我知道解决方案我选择。 – 2009-11-11 19:30:24

1

新界西堆填你可以写你的资料库的方法,使他们只返回客户端的数据为适当的帐号。只需将帐号传递给存储库方法即可。

如果您关心将用户信息传递到存储库方法(如Jabe在他的评论中讨论的那样),那么您可以从存储库返回一个IQueryable,然后运行一个Linq查询来进行安全修整。

+0

:取自

主意? – Omar 2009-11-09 18:58:21

+0

您也可以将管理标志传递给存储库方法。 – 2009-11-09 19:06:03

+0

可能有争议,但存储库不应该知道用户。恕我直言,它应该更像“给身份证,获取数据”。 – Jabe 2009-11-09 19:51:20

0

对于这个特定的例子,A​​zam Sharp在他的blog上有一个可能的解决方案。我在五分钟之前从字面上理解了这篇文章。希望能帮助到你!

+0

再看一遍 - 这并不直接解决您的需求,但我仍然认为它可以适应您正在尝试做的事情。 – 2009-11-09 18:22:47

+0

我对博客海报处理删除的方式并不狂热。删除操作应始终由POST完成,而不是通过GET完成。 – 2009-11-09 18:30:11

+0

@罗伯特 - 我一般同意。我更喜欢这篇文章的总体思路,而不是实施。虽然,BaseController可以做的很好的例子。 – 2009-11-09 18:56:21

0

考虑到您已从配置文件中获得该信息,实际上是否有必要让客户成为路线的一部分?

就处理它而言它是存储库级别(如上所述) - 这可能会有点棘手,因为可能会阻止访问某些业务流程内部所需的数据,也不允许用户访问它。当然,你可以创建单独的过滤/未过滤方法来处理这个问题。而且,这可能是不会混淆客户数据的方式。

大部分时间在我们的应用程序中,它只是被添加/插入/删除的顶级项目,需要以某种方式限制访问。它也只是一个有限的数据集,需要以这种方式进行限制,所以我通常会编写代码,如果违反了该项的访问规则,就会在控制器中抛出某种异常。

如果您的应用程序的规则非常相似,您可以通过很多方法避免重复该代码。一个自定义的ActionFilter或自定义控制器基类都可以想到。如果你的数据库中的每一行都有一个客户端ID或一些这样的方案,另一个选择是让你的域对象实现一个暴露这个ID的接口。然后,您可以编写可重用的代码(混入式扩展方法等),使用此接口作为应用各种安全规则的基础。

+0

路由中不需要客户端。我认为用户{客户和管理员}会更容易。 – 2009-11-09 19:53:16

+0

难道这不会让用户更难吗?要直接访问某个url,他们还必须输入客户端ID。查看上面的代码,您还必须根据已知的“已知”配置文件值验证此值。除非我错过了一些东西(这是很有可能的),似乎所有这些都是多余的。只要配置文件中包含的值是安全和正确的,您就不必处理路由值。 – Krazzy 2009-11-09 20:20:42

+0

我的客户有一个或多个帐号,他们都很熟悉。他们的生命,也就是$$,取决于这些数字。这并不意味着它不是多余的。它只是一个想法,让他们不必总是从列表中选择。 – 2009-11-09 22:46:22