7

我正在实施安全的 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. 当授权检查到处都是这样时,我们如何对 WCF 服务进行单元测试,而我们在单元测试中没有 OperationContext!?(假设我正在尝试直接测试此服务类实现而无需任何 WCF 设置)。

有什么想法吗?

4

3 回答 3

6

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

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

于 2008-09-28T03:42:39.880 回答
6

关于问题 #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 框架:

于 2009-03-17T14:45:12.090 回答
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”类,并针对另一个进行单元测试。

于 2008-09-28T20:06:03.107 回答