1

在我们的 MVC 项目中,我们试图使一切尽可能通用。

因此,我们希望拥有一个涵盖我们所有方法的身份验证类/方法。

例如:以下代码是一个 MVC 类,可以从客户端调用

public class Test
{
    public void Test()
    {
    } 

    public int Test2(int i)
    {
         return i
    }

    public void Test3(string i)
    {
    }
}

我们 Web 服务的客户可以使用服务引用来访问 Test()、Test2() 和 Test3()。

现在我正在寻找一个类、模型、接口或任何其他我可以用来改变对方法的访问(当前使用[PrincipalPermission]属性)以及改变参数值的东西。

例子:

客户 A 来电Test2(150)

类/方法检查客户 A 是否有权访问Test2. 类/方法验证用户,但注意到用户无权访问150. 他只能访问100. 所以类/方法将参数设置为100并让它跟随它的旅程。

客户 B 级Test()

类/方法检查客户 B 是否有权访问Test. 验证后显示用户无权访问,因此引发 SecurityException。

我的问题:

在什么类、接口、属性或任何东西中我能最好地做到这一点?

(ps。作为示例,我只使用了身份验证和参数处理,但我们计划在这个阶段做更多的事情。)

编辑

我注意到大多数(如果不是全部)假设我正在使用 actionResults。所以我想声明这是在一个网络服务中使用的,我们为我们的客户提供来自我们数据库的信息。在向我们的 Web 服务发出请求期间,我们绝不会接触到 ActionResult。(至少,不是我们的客户)

4

7 回答 7

3

身份验证也可以通过一个方面来完成。面向方面的范例旨在尊重那些所谓的横切关注点。以“老式”OO方式实现的横切关注点使您的业务逻辑更难阅读(如上面尼克的示例)甚至更难理解,因为它们不会为您的代码带来任何“直接”好处:

public ActionResult YourAction(int id) {
  if (!CustomerCanAccess(id)) {
    return new HttpUnauthorizedResult();
  }

  /* the rest of your code */
}

你在这里唯一想要的就是/* the rest of your code */,仅此而已。

例如,日志记录、异常处理、缓存和授权之类的东西可以作为一个方面来实现,因此可以在一个点上进行维护。

PostSharp是面向方面的 C# 框架的示例。使用 PostSharp,您可以创建自定义方面,然后注释您的方法(就像您对PrincipalPermissionAttribute. PostSharp 将在编译期间将您的方面代码编织到您的代码中。通过使用 PostSharp 方面,可以挂钩到方法调用来验证调用用户、更改方法参数或抛出自定义异常(有关如何实现的简要说明,请参阅此博客文章)。

于 2013-03-31T18:31:15.660 回答
1

没有处理这种情况的内置属性。

我发现通常最好只做这样的事情:

public ActionResult YourAction(int id) {
  if (!CustomerCanAccess(id)) {
    return new HttpUnauthorizedResult();
  }

  /* the rest of your code */
}

这很简单,也很容易扩展。我想你会发现在很多情况下这就是你所需要的。它还使您的安全断言保持可测试性。您可以编写一个简单地调用该方法的单元测试(没有任何 MVC 管道),并检查调用者是否被授权。

请注意,如果您使用的是 ASP.Net Forms 身份验证,您可能还需要添加:

Response.SuppressFormsAuthenticationRedirect = true;

如果您不希望用户在尝试访问未经授权的资源时被重定向到登录页面。

于 2013-03-29T13:39:45.677 回答
0

我相信你没有得到足够好的答案的原因是因为你的问题有一些模棱两可。首先,您说您有一个从客户端调用的 MVC 类,但您说没有 ActionResults。因此,如果您使用的是 asp.net mvc 框架、web api、wcf 服务或soap (asmx) web 服务,您最好澄清一下。如果我的假设是正确的并且您使用的是 asp.net mvc 框架,那么您如何在不使用操作结果的情况下定义 Web 服务以及您的客户端如何“调用”该服务。我并不是说这是不可能的,或者您可能所做的事情是错误的,但更清晰(和代码)会有所帮助。

如果您使用的是 asp.net mvc3,我的建议是对其进行设计,以便您使用控制器和操作来创建您的 Web 服务。您需要做的就是在操作结果中返回 Json、xml 或您的客户期望的任何其他内容。

如果你这样做了,那么我建议你在一个类中实现你的业务逻辑,就像你在你的问题中发布的那样。此类不应了解您的身份验证或访问级别要求,并且应仅专注于实现所需的业务逻辑并产生正确的结果。

然后,您可以为您的操作方法编写一个自定义操作过滤器,该过滤器可以检查操作参数并确定调用者是否经过身份验证并被授权实际访问该方法。请参阅此处了解如何编写自定义操作过滤器。

如果您认为这听起来像您想要的并且我的假设是正确的,请告诉我,我很乐意发布一些代码来捕获我上面描述的内容。如果我偏离了主题,请澄清问题,我们可能离提出解决方案更近了一步。

ps 您需要的是 AOP 的“思维方式”。PostSharp 作为一个 AOP 工具很棒,但我怀疑 postsharp 在这里能为你做的任何事情是你无法通过稍微不同的架构和正确使用 asp.net mvc 的特性来实现的。

于 2013-04-03T16:58:08.767 回答
0

我不确定我是否理解您的问题,但看起来模型活页夹可以提供帮助。

您的模型绑定器可以注入一个接口,该接口负责确定用户是否有权访问某个方法,并且如果需要,它可以更改作为参数提供的值。

实现 interface 的 ValueProvidersIValueProvider也可能对您的情况有所帮助。

于 2013-03-31T15:48:12.693 回答
0

首先,简单说一下,那个your own methods are probably the most appropriate place to handle input values (adjust/discard) - and with the addition of Authorize and custom filter actions you can get most done, and the 'MVC way'。您也可以采用“OO 方式”并拥有您的ITest接口、调度程序等(您可以获得更多编译器支持——但它更加耦合)。但是,让我们假设您需要更复杂的东西......

我还假设你Test是一个控制器——即使不是,它也可以成为“管道”的一部分(或通过模仿 MVC 所做的),并且考虑到 MVC ......

一种明显的解决方案是通过 ActionFilterAttribute 类 (如 Authorize 等)应用过滤器或操作过滤器 - 通过创建您自己的自定义属性和覆盖OnActionExecuting等。

虽然这很好,但它不会有太大帮助,parameters manipulation因为您必须指定“不合适”的代码 - 或者以某种方式为每个属性注入委托、lambda 表达式。

它基本上an interceptor是您需要的某种类型 - 它允许您附加自己的处理。我做过类似的事情——但是这个人在解释和实施解决方案方面做得很好——所以我建议不要重复大部分内容,而是建议通读一遍。

具有拦截器模式的 ASP.NET MVC 控制器操作(我认为是 Amar)

这样做是将现有的 MVC 机制用于过滤器 - 但它通过不同的“接口”公开它 - 我认为处理输入要容易得多。基本上,你会做的是......

[ActionInterceptor(InterceptionOrder.Before, typeof(TestController), "Test1")]
public void OnTest1(InterceptorParasDictionary<string, object> paras, object result)

参数和更改被传播,你有context一个排序,所以你可以终止进一步的执行 - 或者让这两种方法完成它们的工作等。

同样有趣的是整个模式——这是一种 IOC——你在另一个类/控制器中定义拦截代码——所以不是“装饰”你自己的测试方法——属性和大部分工作都放在外面。

要更改您的参数,您可以执行以下操作...

// I'd create/wrap my own User and make this w/ more support interfaces etc.
if (paras.Count > 0 && Context.User...) 
{
    (paras["id"] as int) = 100;
}            

而且我猜您可以根据自己的情况进一步更改实现。

这只是一个粗略的设计 - 我不知道那里的代码是否已准备好用于生产(它适用于 MVC3,但如果不一样,情况也相似),但它足够简单(当解释时)并且应该可以通过一些小的调整来正常工作你的身边。

于 2013-03-31T13:44:19.050 回答
0

以下是我如何让我的生活变得更简单。

  1. 永远不要使用简单的值作为动作参数。始终创建一个代表动作参数的类。即使只有一个值。我发现我通常最终能够重用这个类。
  2. 确保这个类的所有属性都是可以为空的(这可以防止您遇到自动填写的默认值(整数为 0))并且定义了允许的范围(这可以确保您不必担心负数)
  3. 一旦你有一个代表你的论点的类,把一个验证器扔到一个属性上就变得微不足道了。

问题是你没有传递一个毫无意义的int。它有一个用途,可以是产品编号、帐号等。创建一个将其作为属性的类(例如,具有称为“id”的单个字段的 AccountIdentifier 类)。然后您所要做的就是创建一个 [CurrentUsedCanAccessAccountId] 属性并将其放在该属性上。

您的控制器所要做的就是检查 ModelState.IsValid 是否已经完成。

有更优雅的解决方案,例如向方法添加操作过滤器,该过滤器将根据用户是否有权访问参数的特定值自动重定向,但这会很好用

于 2013-03-25T12:59:55.557 回答
0

首先通过从 ActionFilterAttribute (system.web.mvc) 继承来创建一个属性,然后覆盖 OnActionExecuting 方法并检查用户是否有权限

这个例子

    public class CheckLoginAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (!Membership.IslogedIn)
        {
            filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary
                                {
                                   { "area",""},
                                   { "action", "login" },
                                   { "controller", "user" },
                                   { "redirecturl",filterContext.RequestContext.HttpContext.Request.RawUrl}
                               });
        }
    }
}

然后,将此属性用于您需要检查用户权限的每种方法

public class Test
{
    [ChecklLogin]
    public void Test()
    {
    } 
    [ChecklLogin]
    public int Test2(int i)
    {
         return i
    }
    [ChecklLogin]
    public void Test3(string i)
    {
    }
}
于 2013-04-03T17:11:51.183 回答