对 Wcf 服务的调用被拒绝?这是网络配置的问题吗?
我有一个 WCF 服务...它将驻留在 Azure 上。我通过 web.config 中的以下配置添加了表单身份验证和授权:
<system.web>
<compilation debug="true" targetFramework="4.0" />
<authentication mode="Forms">
<forms loginUrl="blah.svc" timeout="2880" />
</authentication>
<membership defaultProvider="SqlMembershipProvider">
<providers>
<add connectionStringName="blah" applicationName="blah_app" name="SqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" />
</providers>
</membership>
<profile>
<providers>
<add name="SqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="blah" applicationName="blah_app" />
</providers>
</profile>
<roleManager enabled="true" defaultProvider="SqlRoleProvider">
<providers>
<add connectionStringName="blah" applicationName="blah_app" name="SqlRoleProvider" type="System.Web.Security.SqlRoleProvider" />
</providers>
</roleManager>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="wsHttp">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="SqlRoleProvider" />
<serviceCredentials>
<serviceCertificate x509FindType="FindBySubjectName" storeName="My" storeLocation="LocalMachine" findValue="blah_cert" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<services>
<service name="blah_app.blah" behaviorConfiguration="wsHttp">
<endpoint address="" contract="blah_app.iblah" binding="wsHttpBinding" />
</service>
</services>
</system.serviceModel>
我遇到的问题是客户端对 Web 服务的任何调用都被拒绝!
public class Blah:IBlah
{
[PrincipalPermission(SecurityAction.Demand, Role = "BlahOppRole")]
public BlahResponse Blah(BlahRequest BlahRequest)
{
BlahResponse = new BlahResponse();
return response;
}
}
我的客户端是一个 Windows 控制台应用程序。它具有以下配置:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IBlah" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Message">
<transport clientCredentialType="Digest" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" negotiateServiceCredential="true"
algorithmSuite="Default" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://127.0.0.1:89/Blah.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IBlah"
contract="Data.Blah" name="WSHttpBinding_IBlah">
<identity>
<dns value="blah_cert"/>
</identity>
</endpoint>
</client>
I have a WCF service... which will reside on Azure. I added forms authentication and authorization via the following configuration in the web.config:
<system.web>
<compilation debug="true" targetFramework="4.0" />
<authentication mode="Forms">
<forms loginUrl="blah.svc" timeout="2880" />
</authentication>
<membership defaultProvider="SqlMembershipProvider">
<providers>
<add connectionStringName="blah" applicationName="blah_app" name="SqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" />
</providers>
</membership>
<profile>
<providers>
<add name="SqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="blah" applicationName="blah_app" />
</providers>
</profile>
<roleManager enabled="true" defaultProvider="SqlRoleProvider">
<providers>
<add connectionStringName="blah" applicationName="blah_app" name="SqlRoleProvider" type="System.Web.Security.SqlRoleProvider" />
</providers>
</roleManager>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="wsHttp">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="SqlRoleProvider" />
<serviceCredentials>
<serviceCertificate x509FindType="FindBySubjectName" storeName="My" storeLocation="LocalMachine" findValue="blah_cert" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<services>
<service name="blah_app.blah" behaviorConfiguration="wsHttp">
<endpoint address="" contract="blah_app.iblah" binding="wsHttpBinding" />
</service>
</services>
</system.serviceModel>
the problem I am getting is that any of the calls to the web service from the client are comming as Denied!
public class Blah:IBlah
{
[PrincipalPermission(SecurityAction.Demand, Role = "BlahOppRole")]
public BlahResponse Blah(BlahRequest BlahRequest)
{
BlahResponse = new BlahResponse();
return response;
}
}
My client is a windows console app. It has the following configuration:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IBlah" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Message">
<transport clientCredentialType="Digest" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" negotiateServiceCredential="true"
algorithmSuite="Default" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://127.0.0.1:89/Blah.svc"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IBlah"
contract="Data.Blah" name="WSHttpBinding_IBlah">
<identity>
<dns value="blah_cert"/>
</identity>
</endpoint>
</client>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这篇 MSDN 文章 提供了有关如何使用用户名身份验证配置 WsHttpBinding。
基本上,您必须将
TransportWithMessageCredential
(步骤 6)ServiceCredentials
服务行为并配置userNameAuthentication
(步骤 8)This MSDN article gives a good step-by-step instruction on how to configure WsHttpBinding with UserName authentication.
Basically you will have to
TransportWithMessageCredential
(Step 6)ServiceCredentials
service behavior and configureuserNameAuthentication
(Step 8)出色地,
由于我使用的是自签名证书...客户对该证书的真实性大发雷霆。常见错误是 AccessDenied(由于服务配置错误),以及“协商服务凭证时发生错误...”或类似的错误。长话短说,在阅读了这个好人的帖子后(谢谢 Dev @ Work)Dev @ Work 我能够修改他的工作并通过服务上的成员资格和角色提供程序添加 ASP.NET 表单身份验证和授权。
总而言之,Dev @ Work 的观点非常有道理。 WCF 客户端会对自签名证书大喊大叫。使 wcf 服务在开发服务器上发挥作用的技巧是向服务客户端撒谎,告知用于对客户端凭据进行编码的证书的真实性。为此,任何 wcf 客户端都必须为其 serviceEndpoint 提供 behaviorConfiguration,并使用自定义证书验证机制来验证服务器的证书。这是通过创建一个继承自 System.IdentityModel.Selectors.X509CertificateValidator 的对象并重写该对象的
Validate()
方法来完成的。如果所述对象不抛出错误,则验证成功:自定义验证器:
Well,
Since I was using a self signed certificate... the client was throwing a fit about the authenticity of that certificate. Common errors were AccessDenied, (due to misconfiguration of the service), as well "Error occured while negotiating the service credential..." or something along the lines. Long story short, after reading the post of this fine fellow (Thank you Dev @ Work) Dev @ Work I was able to modify his work and add ASP.NET forms authentication and authorization via Membership and Role providers on the service.
To sum it up, Dev @ Work had a very valid point. WCF clients will scream about self signed certificates. The trick to making a wcf service useful on a dev server is to lie to the service clients about the authenticity of the certificate used to encode the client's credentials. To do so, any wcf client has to have a behaviorConfiguration to its serviceEndpoint and use custom certificate validation mechanism to authenticate the server's certificate. This is done by creating an object that inherits from the System.IdentityModel.Selectors.X509CertificateValidator and by overriding the
Validate()
method of said object. The validation is successful if the said object doesn't throw errors:And the custom validator: