WCF Security之MembershipProvider+RoleProvider方案
对于web应用(包括web站点及web服务)的安全,我们首先想到的和见到的是,让客户提供凭据(最常见的是用户名和密码),然后服务端对客户提供的凭据进行验证,验证通过后,在具体的方法调用或页面请求时,根据验证通过的客户身份进行授权检查,授权通过,则执行客户的请求;反之则拒绝客户的请求。这就是一般验证及授权的思路。
如果这样还不能安全要求,那只好再启用传输层加密,即SSL了。实际上在WCF中,验证方式也被分为两个层次:Transport和Message。在传输层加密数据,在消息层提供凭据验证及授权。本文就准备介绍客户端在消息层传入用户凭据,服务端通过MembershipProvider进行验证,通过RoleProvider进行授权,然后辅以传输层加密的方案。
这个方案针对于WCF服务,为了便于客户调用,而又加强传输层安全,所以选择了SSL,另外调用WCF服务又需要提供身份验证及授权,尤其针对凭据信息自定义的要求,客户端凭据选择UserName类型。
这个方案的好处是什么呢?TransportWithMessageCredential确保了传输上的安全,并提供了客户端凭据。而对客户端凭据的验证和授权支持自定义方式,所以不管用什么实现rbac,都可以使用这套方案来实现权限控制。另外,在代码中实现权限控制也比较简单,即使用PrincipalPermissionAttribute。
还是让我们开始看看demo吧。
首先然我们定义一个ServiceContract:
[ServiceContract]public inte易做图ce ITestService
{
[OperationContract]
string GetData(int value);
}
我们给这个ITestService一个简单的实现:
view sourceprint?public class TestService : ITestService{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
}
接下来,让我们提供配置信息:
1)Binding配置
view sourceprint?<wsHttpBinding><binding name="wsHttpBinding1">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" realm="" />
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
2)Service配置
view sourceprint?<service name="TestService.TestService" behaviorConfiguration="securityBehavior"><endpoint address=""
binding="wsHttpBinding"
bindingConfiguration ="wsHttpBinding1"
contract ="TestBase.ITestService"
name ="testService" />
<endpoint address="mex"
binding="mexHttpsBinding"
contract="IMetadataExchange" />
</service>
3)MembershipProvider及RoleProvider配置
view sourceprint?<system.web><roleManager enabled="true" defaultProvider ="MyProvider">
<providers>
<add name="MyRoleProvider" type="TestBase.MyRoleProvider,TestBase"/>
</providers>
</roleManager>
<membership>
<providers>
<add name="MyMembershipProvider" type="TestBase.MyMembershipProvider,TestBase"/>
</providers>
</membership>
</system.web>
4)Behavior配置
view sourceprint?<serviceBehaviors><behavior name="securityBehavior">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="MembershipProvider" membershipProviderName="MyMembershipProvider"/>
</serviceCredentials>
<serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="MyRoleProvider" />
</behavior>
</serviceBehaviors>
好了,需要的类及配置都已准备好了,然后在IIS中,确保目标Web Site中包含https绑定,并且https绑定指向一个证书。在该Web Site中建立一个Application: TestService。浏览vc">https://localhost/TestService/TestService.svc,可以正常浏览。
接下来,实现客户端调用代码:
view sourceprint?try{
TestServiceReference.TestServiceClient testServiceClient = new TestServiceReference.TestServiceClient ("testService");
testServiceClient .ClientCredentials.UserName.UserName = "userName";
testServiceClient .ClientCredentials.UserName.Password = "password";
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, errors) =>
{
return true;
};
string result = testServiceClient .GetData(3456);
Console.WriteLine("result : {0}", result);
}
catch (MessageSecurityException ex)
{
//authenticated failed
Console.WriteLine(ex.Message);
}
catch(SecurityAccessDeniedException ex)
{
//authorized failed
Console.WriteLine(ex.Message);
}
catch(FaultException ex)
{
Console.WriteLine(ex.Message);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
Console.ReadLine();
运行,服务可以正常访问。但是权限控制还没有加到服务端代码上,在TestService的GetData方法上加上PrincipalPermissionAttribute:
view sourceprint?public class TestService : ITestService{
[PrincipalPermission(SecurityAction.Demand, Role = "getData")]
public string GetData(int value)
{
补充:综合编程 , 其他综合 ,