【问题标题】:WCF Service authorization patternsWCF 服务授权模式
【发布时间】:2013-10-02 20:31:51
【问题描述】:

我正在实施一个安全的 WCF 服务。使用用户名/密码或 Windows 凭据完成身份验证。该服务托管在 Windows 服务进程中。现在,我正在尝试找出为每个服务操作实施授权的最佳方式。

例如,考虑以下方法:

public EntityInfo GetEntityInfo(string entityId);

您可能知道,在 WCF 中,有一个 OperationContext 对象,您可以从中检索调用者/客户端传入的安全凭据。现在,身份验证在方法中的第一行被调用时已经完成。但是,如果决定取决于输入数据本身,我们如何实施授权呢?例如,在上述情况下,假设“管理员”用户(其权限等存储在数据库中)被允许获取实体信息,而其他用户不应该被允许......我们将授权检查放在哪里?

假设我们将它放在方法的第一行,如下所示:

CheckAccessPermission(PermissionType.GetEntity, user, entityId) //user is pulled from the current OperationContext

现在,有几个问题:

  1. 我们是在授权检查之前还是在授权检查内部验证 entityId(例如检查 null/空值等)?换句话说,如果授权检查应该包含在每个方法中,这是一个好的模式吗?哪个应该首先发生 - 参数验证或授权?

  2. 当授权检查无处不在,而我们在单元测试中没有 OperationContext 时,我们如何对 WCF 服务进行单元测试!? (假设我正在尝试直接测试此服务类实现,而无需任何 WCF 设置)。

各位有什么想法吗?

【问题讨论】:

    标签: c# .net wcf authorization


    【解决方案1】:

    对于问题1,最好先进行授权。这样,您就不会将验证错误消息泄露给未经授权的用户。

    顺便说一句,您也许可以连接到 WCF 对 ASP.NET 角色提供程序的开箱即用支持,而不是使用本地开发的身份验证方法(我假设这就是您的 CheckAccessPermission)。完成此操作后,您将通过 OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.IsInRole() 执行授权。 PrimaryIdentity 是一个 IPrincipal。

    【讨论】:

    • 谢谢保罗。首先进行授权的问题是:如果我们需要根据输入参数检查权限,我们如何授权用户?在我们将其用于授权之前,我们不需要先验证这些参数吗?
    • 授权应该只依赖于用户的身份。如果它依赖于输入参数,那么调用者可以发送它需要的任何值来获得它想要的授权,所以你的授权检查变得毫无意义。
    • 没有。假设我想访问 id 为“abc1”的对象。我是“用户1”。授权决定“用户 1”是否可以访问对象“abc1”。所以首先要做的是验证包含对象 id 字符串的参数!
    【解决方案2】:

    关于问题 #2,我将使用依赖注入来执行此操作并设置您的服务实现,如下所示:

    class MyService : IMyService
    {
        public MyService() : this(new UserAuthorization()) { }
        public MyService(IAuthorization auth) { _auth = auth; }
    
        private IAuthorization _auth;
    
        public EntityInfo GetEntityInfo(string entityId)
        {
                _auth.CheckAccessPermission(PermissionType.GetEntity, 
                        user, entityId);
    
                //Get the entity info
        }
    }
    

    请注意,IAuthorization 是您要定义的接口。

    因为您将直接测试服务类型(即,不在 WCF 托管框架内运行它),您只需将服务设置为使用允许所有调用的虚拟 IAuthorization 类型。然而,一个更好的测试是模拟 IAuthorization 并测试它在何时以及使用您期望的参数被调用。这使您可以测试对授权方法的调用以及方法本身是否有效。

    将授权分成自己的类型还可以让您更轻松地单独测试它是否正确。根据我(虽然有限)的经验,使用 DI“模式”可以让您更好地分离类型中的关注点和可测试性,并带来更简洁的界面(这显然是有争议的)。

    我首选的模拟框架是RhinoMocks,它是免费的并且具有非常流畅的界面,但还有很多其他的。如果您想了解更多关于 DI 的信息,这里有一些很好的入门书和 .Net 框架:

    【讨论】:

      【解决方案3】:

      对于问题1,绝对要先授权。在授权之前不应执行任何代码(在您的控制范围内)以保持最严格的安全性。上面保罗的例子非常好。

      对于问题 2,您可以通过子类化您的具体服务实现来解决这个问题。如上所述,使用抽象的“CheckPermissions”方法使真正的业务逻辑实现成为一个抽象类。然后创建 2 个子类,一个供 WCF 使用,一个(在未部署的 DLL 中非常隔离)返回 true(或您希望在单元测试中执行的任何操作)。

      示例(请注意,这些不应该在同一个文件甚至 DLL 中!):

      public abstract class MyServiceImpl
      {
          public void MyMethod(string entityId)
          {
              CheckPermissions(entityId);
              //move along...
          }
          protected abstract bool CheckPermissions(string entityId);
      }
      
      public class MyServiceUnitTest
      {
          private bool CheckPermissions(string entityId)
          {
              return true;
          }
      }
      
      public class MyServiceMyAuth
      {
          private bool CheckPermissions(string entityId)
          {
              //do some custom authentication
              return true;
          }
      }
      

      然后您的 WCF 部署使用“MyServiceMyAuth”类,然后您针对另一个进行单元测试。

      【讨论】:

        猜你喜欢
        • 2011-04-09
        • 1970-01-01
        • 2013-03-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多