WCF服务授权模式
我正在实现一个安全的WCF服务。 使用用户名/密码或Windows凭据进行身份validation。 该服务托管在Windows服务进程中。 现在,我正在尝试找出为每个服务操作实现授权的最佳方法。
例如,请考虑以下方法:
public EntityInfo GetEntityInfo(string entityId);
您可能知道,在WCF中,有一个OperationContext对象,您可以从中检索调用方/客户端传入的安全凭据。 现在,在调用方法的第一行时, 身份validation已经完成。 但是,如果决策取决于输入数据本身,我们如何实施授权? 例如,在上述情况下,说’admin’用户(其权限等存储在数据库中),允许获取实体信息,不允许其他用户…我们在哪里进行授权检查?
假设我们把它放在方法的第一行,如下所示:
CheckAccessPermission(PermissionType.GetEntity, user, entityId) //user is pulled from the current OperationContext
现在,有几个问题:
-
我们是否在授权检查或INSIDE授权检查之前validationentityId(例如检查null /空值等)? 换句话说,如果每个方法都应该包含授权检查,那么这是一个好的模式吗? 哪个应该首先发生 – 参数validation或授权?
-
当授权检查遍布这样的地方时,我们如何对WCF服务进行unit testing,并且我们在unit testing中没有OperationContext!? (假设我试图在没有任何WCF设置的情况下直接测试这个服务类实现)。
任何想法的家伙?
问题1,绝对先做授权。 在授权之前,不应执行任何代码(在您的控制范围内)以保持最严格的安全性。 上面保罗的例子很棒。
对于问题2,您可以通过子类化具体的服务实现来处理这个问题。 如上所述,使用抽象的“CheckPermissions”方法将真正的业务逻辑实现作为抽象类。 然后创建2个子类,一个用于WCF使用,另一个(在非部署的DLL中非常孤立)返回true(或者您希望它在unit testing中执行的任何操作)。
示例(注意,这些不应该在同一个文件中,甚至不应该在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”类,并对另一个进行unit testing。
对于问题1,最好先执行授权。 这样,您就不会将validation错误消息泄漏回未经授权的用户。
顺便说一下,您可能能够连接到WCF对ASP.NET角色提供程序的开箱即用支持,而不是使用自行开发的身份validation方法(我假设您的CheckAccessPermission是什么)。 完成此操作后,您将通过OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.IsInRole()执行授权。 PrimaryIdentity是一个IPrincipal。
关于问题#2,我会使用dependency injection执行此操作并设置您的服务实现,如下所示:
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框架:
- DI的Martin Fowler
- 杰里米米勒在DI上
- Scott Hanselman的DI容器清单
- 我个人最喜欢的DI容器: Castle Project Windsor Container
- 将’Set Next Statement’强制为’if’块时CLR System.NullReferenceException
- 无法使用Json.NET反复使用多个构造函数对类进行反序列化
- 哪个.NET平台以及哪个版本的Windows在字符类方面支持哪个版本的Unicode?
- 有没有办法从.NET应用程序中的WebBrowser控件内启用IE8开发人员工具
- 如何从if语句中的布尔值中断出if语句
- 为什么我在Visual Studio 2010中找不到或使用UrlEncode?
- Microsoft图表控件和X轴时间刻度格式
- 在上传文件控件中恢复
- 目标框架中缺少“WindowsBase”,“PresentationCore”,“PresentationFramework”