C# WCF 服务授权模式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/145025/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WCF Service authorization patterns
提问by Krishna
I'm implementing a secure WCF service. Authentication is done using username / password or Windows credentials. The service is hosted in a Windows Service process. Now, I'm trying to find out the best way to implement authorizationfor each service operation.
我正在实施一个安全的 WCF 服务。身份验证是使用用户名/密码或 Windows 凭据完成的。该服务托管在 Windows 服务进程中。现在,我正在尝试找出为每个服务操作实施授权的最佳方式。
For example, consider the following method:
例如,请考虑以下方法:
public EntityInfo GetEntityInfo(string entityId);
As you may know, in WCF, there is an OperationContext object from which you can retrieve the security credentials passed in by the caller/client. Now,authenticationwould have already finished by the time the first line in the method is called. However, how do we implement authorization if the decision depends on the input data itself? For example, in the above case, say 'admin' users(whose permissions etc are stored in a database), are allowed to get entity info, and other users should not be allowed... where do we put the authorization checks?
您可能知道,在 WCF 中,有一个 OperationContext 对象,您可以从中检索调用方/客户端传入的安全凭据。现在,在调用方法中的第一行时,身份验证已经完成。但是,如果决策取决于输入数据本身,我们如何实现授权?例如,在上面的例子中,假设“管理员”用户(其权限等存储在数据库中)被允许获取实体信息,而其他用户不应该被允许......我们在哪里进行授权检查?
Say we put it in the first line of the method like so:
假设我们把它放在方法的第一行,像这样:
CheckAccessPermission(PermissionType.GetEntity, user, entityId) //user is pulled from the current OperationContext
Now, there are a couple of questions:
现在,有几个问题:
Do we validate the entityId (for example check null / empty value etc) BEFORE the authorization check or INSIDE the authorization check? In other words, if authorization checks should be included in every method, is that a good pattern? Which should happen first - argument validation or authorization?
How do we unit test a WCF service when authorization checks are all over the place like this, and we don't have an OperationContext in the unit test!? (Assuming I'm tryin to test this service class implementation directly without any of the WCF setup).
我们是否在授权检查之前或在授权检查内部验证 entityId(例如检查空值/空值等)?换句话说,如果每个方法都应该包含授权检查,这是一个好的模式吗?哪个应该先发生 - 参数验证或授权?
当授权检查像这样到处都是,而我们在单元测试中没有 OperationContext 时,我们如何对 WCF 服务进行单元测试!?(假设我试图在没有任何 WCF 设置的情况下直接测试这个服务类实现)。
Any ideas guys?
有什么想法吗?
采纳答案by TheSoftwareJedi
For question 1, absolutely do authorization first. No code (within your control) should execute before authorization to maintain the tightest security. Paul's example above is excellent.
对于问题1,绝对先授权。在授权之前不应执行任何代码(在您的控制范围内)以保持最严格的安全性。保罗上面的例子非常好。
For question 2, you could handle this by subclassing your concrete service implementation. Make the true business logic implementation an abstract class with an abstract "CheckPermissions" method as you mention above. Then create 2 subclasses, one for WCF use, and one (very isolated in a non deployed DLL) which returns true (or whatever you'd like it to do in your unit testing).
对于问题 2,您可以通过子类化您的具体服务实现来处理此问题。如上所述,使真正的业务逻辑实现成为具有抽象“CheckPermissions”方法的抽象类。然后创建 2 个子类,一个用于 WCF,一个(在未部署的 DLL 中非常孤立)返回 true(或您希望它在单元测试中执行的任何操作)。
Example (note, these shouldn't be in the same file or even DLL though!):
示例(注意,这些不应该在同一个文件中,甚至不应该在 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;
}
}
Then your WCF deployment uses the class "MyServiceMyAuth", and you do your unit testing against the other.
然后您的 WCF 部署使用类“MyServiceMyAuth”,并且您针对另一个进行单元测试。
回答by Paul Lalonde
For question 1, it's best to perform authorization first. That way, you don't leak validation error messages back to unauthorized users.
对于问题1,最好先进行授权。这样,您就不会将验证错误消息泄露给未经授权的用户。
BTW, instead of using a home-grown authentication method (which I assume is what your CheckAccessPermission is), you might be able to hook up to WCF's out-of-the-box support for ASP.NET role providers. Once this is done, you perform authorization via OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.IsInRole(). The PrimaryIdentity is an IPrincipal.
顺便说一句,您可以使用 WCF 对 ASP.NET 角色提供程序的开箱即用支持,而不是使用自己开发的身份验证方法(我假设您的 CheckAccessPermission 就是这种方法)。完成此操作后,您可以通过 OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.IsInRole() 执行授权。PrimaryIdentity 是一个 IPrincipal。
回答by akmad
About question #2, I would do this using Dependency Injection and set up your service implementation something like this:
关于问题#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
}
}
Note that IAuthorization is an interface that you would define.
请注意,IAuthorization 是您要定义的接口。
Because you are going to be testing the service type directly (that is, without running it inside the WCF hosting framework) you simply set up your service to use a dummy IAuthorization type that allows all calls. However, an even BETTER test is to mock the IAuthorization and test that it is called when and with the parameters that you expect. This allows you to test that your calls to the authorization methods are valid, along with the method itself.
因为您将直接测试服务类型(即,不在 WCF 托管框架内运行它),您只需将服务设置为使用允许所有调用的虚拟 IAuthorization 类型。但是,更好的测试是模拟 IAuthorization 并测试它在何时以您期望的参数被调用。这允许您测试对授权方法的调用以及方法本身是否有效。
Separating the authorization into it's own type also allows you to more easily test that it is correct in isolation. In my (albeit limited) experience, using DI "patterns" give you vastly better separation of concerns and testability in your types as well as leading to a cleaner interface (this is obviously open to debate).
将授权分成自己的类型还可以让您更轻松地单独测试它是否正确。在我(尽管有限)的经验中,使用 DI“模式”可以让您在类型中更好地分离关注点和可测试性,并带来更清晰的界面(这显然是有争议的)。
My preferred mocking framework is RhinoMockswhich is free and has very nice fluent interface but there are lots of others out there. If you'd like to know more about DI here are some good primers and .Net frameworks:
我最喜欢的模拟框架是RhinoMocks,它是免费的并且具有非常流畅的界面,但还有很多其他框架。如果您想了解更多关于 DI 的信息,这里有一些不错的入门书和 .Net 框架:
- Martin Fowler on DI
- Jeremy Miller on DI
- Scott Hanselman's List of DI Containers
- My personal favorite DI container: The Castle Project Windsor Container