WCF中的OneWay操作是否与ClientCertificateMappingAuthorization兼容?

时间:2019-01-11 15:13:27

标签: wcf iis-7 client-certificates isoneway

我用一种void方法制作了WCF,并将其部署在IIS上;它将正常工作(服务响应为代码202),直到我将其置于带有客户端证书身份验证的SSL下:在这种情况下,该操作背后的代码未执行且服务器响应为200。似乎未引发异常(无失败请求)被跟踪,事件查看器上没有错误),但是我无法执行被调用的方法

这是WCF的实现和配置:

namespace WcfTestService
{
    [ServiceContract]
    public interface IWcfTestService
    {
        [OperationContract(IsOneWay =true)]
        void OneWay(int value);

    }

    [ServiceBehavior]
    public class Service1 : IWcfTestService
    {
        [OperationBehavior]
        public void OneWay(int value)
        {
            Trace.TraceInformation(DateTime.Now.ToString() + " Oneway method invoked!" );
        }
    }
}


<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.web>
        <compilation debug="true" targetFramework="4.0" />
    </system.web>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="WcfTestBinding" messageEncoding="Text" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" maxBufferPoolSize="50000000" maxReceivedMessageSize="50000000">
                    <readerQuotas maxDepth="500000000" maxStringContentLength="500000000" maxArrayLength="500000000" maxBytesPerRead="500000000" maxNameTableCharCount="500000000" />
                    <security mode="Transport">
                        <transport clientCredentialType="Certificate" />
                    </security>
                </binding>
            </basicHttpBinding>
        </bindings>
        <services>
            <service name="WcfTestService.Service1" behaviorConfiguration="WcfTestBehaviors">
                <endpoint address="" binding="basicHttpBinding" bindingConfiguration="WcfTestBinding" contract="WcfTestService.IWcfTestService" />
                <endpoint contract="IMetadataExchange" binding="mexHttpsBinding" address="mex" />
            </service>
        </services>
        <protocolMapping>
            <add binding="wsHttpBinding" scheme="https" />
        </protocolMapping>

        <behaviors>
            <serviceBehaviors>
                <behavior name="WcfTestBehaviors">
                    <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="true" />
                    <serviceThrottling maxConcurrentCalls="500" maxConcurrentInstances="500" maxConcurrentSessions="500" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    </system.serviceModel>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true" />
        <directoryBrowse enabled="true" />
        <security>
            <authentication>
                <anonymousAuthentication enabled="true" />
                <iisClientCertificateMappingAuthentication enabled="true">
                    <oneToOneMappings>
                        <clear />
                    </oneToOneMappings>
                </iisClientCertificateMappingAuthentication>
            </authentication>
            <authorization>
                <remove users="*" roles="" verbs="" />
                <add accessType="Allow" users="" roles="Users" />
            </authorization>
        </security>
        <tracing>
            <traceFailedRequests>
                <remove path="*" />
                <add path="*">
                    <traceAreas>
                        <add provider="WWW Server" areas="Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,FastCGI" verbosity="Verbose" />
                    </traceAreas>
                    <failureDefinitions timeTaken="00:00:00" statusCodes="401.2,202" />
                </add>
            </traceFailedRequests>
        </tracing>
    </system.webServer>
    <system.diagnostics>
        <switches>
            <add name="DataMessagesSwitch" value="1" />
            <add name="TraceLevelSwitch" value="4" />
        </switches>
        <trace autoflush="true" indentsize="4">
            <listeners>
                <add name="WcfTestServiceTraceListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="logs\WcfTestService.txt" />
                <remove name="Default" />
            </listeners>
        </trace>
    </system.diagnostics>
</configuration>

客户端代码及其配置:

static bool Test()
        {
            string certPath = @"C:\myCertName.pfx";
            string pwdValue = "myPassword";
            bool res = false;
            EndpointAddress newEP = new EndpointAddress("https://myservername/WcfTestService");
            BasicHttpsBinding newBind = new BasicHttpsBinding();

            newBind.Security.Mode = BasicHttpsSecurityMode.Transport;
            newBind.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;

            srvRefTest.WcfTestServiceClient myWS = new srvRefTest.WcfTestServiceClient(newBind,newEP);

            System.Net.ServicePointManager.ServerCertificateValidationCallback +=
                            (se, cert, chain, sslerror) =>
                            {
                                return true;
                            };

            X509Certificate2 ccert = new X509Certificate2(certPath, pwdValue);
            myWS.ClientCredentials.ClientCertificate.Certificate = ccert;
            myWS.OneWay(1);
            return res;
        }

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_IWcfTestService">
                    <security mode="Transport">
                        <transport clientCredentialType="Certificate" />
                        <message clientCredentialType="UserName" />
                    </security>
                </binding>
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="https://myservername/WcfTestService/WcfTestService.svc"
                binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IWcfTestService"
                contract="srvRefTest.IWcfTestService" name="BasicHttpBinding_IWcfTestService" />
        </client>
    </system.serviceModel>
</configuration>        

在服务器日志上,我可以看到此呼叫:

2019-01-11 14:45:01 W3SVC1 10.0.0.4 POST /WcfTestService - 443 SDI_user 130.0.139.146 - 200 0 0 187

其中SDI_user是IIS中manyToOneMapping部分中指定的用户名,如图所示: (https://drive.google.com/open?id=1gGN6HrIDC9u160FuWx6MBwgi7MW7ppRS

3 个答案:

答案 0 :(得分:0)

最好的办法是在服务器端和客户端都添加WCF跟踪 https://docs.microsoft.com/en-us/dotnet/framework/wcf/diagnostics/tracing/configuring-tracing 这应该为您提供正在发生的事情的详细信息。如果需要,请在此处发布svclog文件

答案 1 :(得分:0)

我查看了您的配置,并想知道为什么不以标准方式使用客户端证书-不了解安全模式-传输同时进行传输和邮件安全 我建议您遵循以下示例:https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/transport-security-with-certificate-authentication 使用wsHttpBinding外观进行比较:https://www.codeproject.com/Articles/36396/Difference-between-BasicHttpBinding-and-WsHttpBind

答案 2 :(得分:0)

感谢所有人(尤其是oshvartz);我只是找到了原因:在客户端代码中,我必须指定.svc文件的完整端点地址。这是完整的代码和配置。

WCF的实现和配置:

namespace WcfTestService
{
    [ServiceContract]
    public interface IWcfTestService
    {
        [OperationContract(IsOneWay =true)]
        [XmlSerializerFormat()]
        void OneWay(int value);
    }
}

namespace WcfTestService
{
     [ServiceBehavior]
    public class Service1 : IWcfTestService
    {

        [OperationBehavior]
        public void OneWay(int value)
        {
            Trace.TraceInformation(DateTime.Now.ToString() + " " + "Oneway method invoked! Parameter= " + value.ToString());
            Trace.Flush();
        }
    }
}

WCF配置:

<configuration>
    <system.web>
        <compilation debug="true" targetFramework="4.0" />
    </system.web>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WcfTestBinding" messageEncoding="Mtom" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" maxBufferPoolSize="50000000" maxReceivedMessageSize="50000000">
                    <readerQuotas maxDepth="500000000" maxStringContentLength="500000000" maxArrayLength="500000000" maxBytesPerRead="500000000" maxNameTableCharCount="500000000" />
                    <security mode="TransportWithMessageCredential">
                        <message clientCredentialType="Certificate" />
                        <transport clientCredentialType="Certificate" />
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <services>
            <service name="WcfTestService.Service1" behaviorConfiguration="WcfTestBehaviors">
                <endpoint address="" binding="wsHttpBinding" bindingConfiguration="WcfTestBinding" contract="WcfTestService.IWcfTestService" />
                <endpoint contract="IMetadataExchange" binding="mexHttpsBinding" address="mex" />
            </service>
        </services>
        <behaviors>
            <serviceBehaviors>
                <behavior name="WcfTestBehaviors">
                    <serviceMetadata httpsGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
        <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
    </system.serviceModel>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true" />
        <directoryBrowse enabled="true" />
        <security>
                        <authentication>
                <anonymousAuthentication enabled="true" />
            </authentication>
            <authorization>
                <remove users="*" roles="" verbs="" />
                <add accessType="Allow" users="myuser" />
            </authorization>
        </security>
        <tracing>
            <traceFailedRequests>
                <remove path="*" />
                <add path="*">
                    <traceAreas>
                        <add provider="WWW Server" areas="Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,FastCGI" verbosity="Verbose" />
                    </traceAreas>
                    <failureDefinitions timeTaken="00:00:00" statusCodes="401-500" />
                </add>
            </traceFailedRequests>
        </tracing>
    </system.webServer>
   <system.diagnostics>
        <switches>
            <add name="DataMessagesSwitch" value="1" />
            <add name="TraceLevelSwitch" value="4" />
        </switches>
        <trace autoflush="true" indentsize="4">
            <listeners>
                <add name="WCFConsumerTraceListener" type="System.Diagnostics.TextWriterTraceListener" 
                     initializeData="logs\WcfTestService.txt" />
            </listeners>
        </trace>
    </system.diagnostics>
</configuration>

客户端实现:

static void Test1Remoto()
        {
            EndpointAddress newEP = new EndpointAddress("https://mydomain/WcfTestService/WcfTestService.svc");
            BasicHttpsBinding newBind = new BasicHttpsBinding();

            newBind.Security.Mode = BasicHttpsSecurityMode.Transport;
            newBind.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;

            srvRefTest.WcfTestServiceClient myWS = new srvRefTest.WcfTestServiceClient(newBind,newEP);

            System.Net.ServicePointManager.ServerCertificateValidationCallback +=
                            (se, cert, chain, sslerror) =>
                            {
                                return true;
                            };

            X509Certificate2 ccert = new X509Certificate2(certPath, pwdValue);
            myWS.ClientCredentials.ClientCertificate.Certificate = ccert;
            myWS.OneWay(1);
            myWS.Close();
        }

客户端配置:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_IWcfTestService" messageEncoding="Mtom">
                    <security mode="TransportWithMessageCredential">
                        <transport clientCredentialType="None" />
                        <message clientCredentialType="Windows" />
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="https://mydomain/WcfTestService/WcfTestService.svc"
                binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IWcfTestService"
                contract="srvRefTest.IWcfTestService" name="WSHttpBinding_IWcfTestService" />
        </client>
    </system.serviceModel>
</configuration>