Kri*_*hna 7 .net c# wcf authorization
我正在实现一个安全的WCF服务.使用用户名/密码或Windows凭据进行身份验证.该服务托管在Windows服务进程中.现在,我正在尝试找出为每个服务操作实现授权的最佳方法.
例如,请考虑以下方法:
public EntityInfo GetEntityInfo(string entityId);
Run Code Online (Sandbox Code Playgroud)
您可能知道,在WCF中,有一个OperationContext对象,您可以从中检索调用方/客户端传入的安全凭据.现在,在调用方法的第一行时,身份验证已经完成.但是,如果决策取决于输入数据本身,我们如何实施授权?例如,在上述情况下,说'admin'用户(其权限等存储在数据库中),允许获取实体信息,不允许其他用户...我们在哪里进行授权检查?
假设我们把它放在方法的第一行,如下所示:
CheckAccessPermission(PermissionType.GetEntity, user, entityId) //user is pulled from the current OperationContext
Run Code Online (Sandbox Code Playgroud)
现在,有几个问题:
我们在授权检查之前验证entityId(例如检查null /空值等)还是INSIDE授权检查?换句话说,如果每个方法都应该包含授权检查,那么这是一个好的模式吗?哪个应该首先发生 - 参数验证或授权?
当授权检查遍布这样的地方时,我们如何对WCF服务进行单元测试,并且我们在单元测试中没有OperationContext!?(假设我试图在没有任何WCF设置的情况下直接测试这个服务类实现).
有什么想法吗?
对于问题1,最好先执行授权.这样,您就不会将验证错误消息泄漏回未经授权的用户.
顺便说一句,您可能能够连接到WCF对ASP.NET角色提供程序的开箱即用支持,而不是使用自行开发的身份验证方法(我假设它是您的CheckAccessPermission).完成此操作后,您将通过OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.IsInRole()执行授权.PrimaryIdentity是一个IPrincipal.
关于问题#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
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,IAuthorization是您要定义的接口.
因为您将直接测试服务类型(即,不在WCF托管框架内运行它),您只需将服务设置为使用允许所有调用的虚拟IAuthorization类型.然而,更好的测试是模拟IAuthorization并测试它是否与您期望的参数一起调用.这允许您测试您对授权方法的调用是否有效,以及方法本身.
将授权分成它自己的类型还可以让您更容易地单独测试它是否正确.在我(尽管有限)的经验中,使用DI"模式"可以更好地分离您的类型中的关注点和可测试性,并导致更清晰的界面(这显然是有争议的).
我首选的模拟框架是RhinoMocks,它是免费的,并且具有非常好的流畅界面,但是还有很多其他的.如果你想了解更多关于DI的信息,可以参考一些优秀的引物和.Net框架:
对于问题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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,您的 WCF 部署使用“MyServiceMyAuth”类,并针对其他类进行单元测试。