• .Net调用Java端带有WS-Security支持的Web Service各方案实战【转】


    原文:http://www.xuebuyuan.com/641669.html

    到现在为止,我们AEP平台已经发布很长一段时间了,也有很多ISV接入并上线了,就语言而言,目前主要有三类:Java、.Net、Php;Java和Php的调用不存在很复杂的问题,但是.Net就要相对复杂不少, 现在已上线的ISV采用的是.Net SDK 2.0 + WSE 2.0【Web Services Enhancements】,但是随着.Net 3.0和3.5的普及,我们需要支持更多的.Net接入方案;

    总的来说,针对不同的.Net SDK版本有三种实现来满足对带有WS-Security支持的Web Service调用,即WSE 2.0、WSE 3.0、WCF【Windows Communication Foundation】;其中WSE 2.0针对的是VS 2003版本,WSE 3.0针对的是VS 2005版本,WCF针对的是VS 2008,从SDK要求来看,WSE 2.0和3.0是2.0,而WCF要求是3.0或3.5;前面我的同事已经将WSE 2.0调通,但是对WSE 3.0始终无法调通,具体可以参见《Web Service 、WS-Security、Java和.net的互通(在路上-基于SCA规范的应用服务框架成长记之四》;而WCF经过微软研究院几个月的调试,也已经调通,具体可以参见《.Net在Alibaba的AEP平台上的应用》;不幸的是,针对这两种配置方案经测试是不兼容的,因为不止是.Net客户端调整配置和代码,Java服务端仍然要做出调整,这对于我们的系统侵入是非常大的,因为现在已经有ISV采用WSE 2.0实现在生产环境运行了,要想在服务端做出调整的话必须要做到无缝升级,也即线上所有的ISV客户端无需做任何修改,否则这个升级代价会非常高;

    功夫不负有心人啊,经过几天的研究,终于让我找到一个更加有效的解决方案,在新的配置方案下,WSE 2.0、WSE 3.0、WCF全部都可以调试通过,并且对Java端没有任何影响,Php的调用经确认也不存在任何问题;服务端OutflowSecurity配置文件修改如下:其中,1)items中添加了Timestamp的配置,并且在Signature之前,这是为了满足WCF的测试而特意设置的,幸好这不影响其他方案的调试;
    2)signatureKeyIdentifier设置为DirectReference,该配置项在前面已经提到过,他和X509KeyIdentifier一样,是将签名者的证书公共部分直接通过soap xml传递给客户端,然后客户端再和他本地的公钥证书做对比,通过之后进行签名验证;关于该配置项,在Java服务端WSS4J的javadoc中描述有误,javadoc中说该项只允许两个值:IssuerSerial和SKIKeyIdentifier,但实际上他可以取5种值,这可能是导致很多人无法在.Net环境调试通过的原因;
    3)signatureParts种指定了参与签名的是Timestamp和body部分,这也是WCF所特别需要的,因为WCF要求soap xml种的header部分都要参与签名;

    <items>Timestamp Signature</items>
    <signatureKeyIdentifier>DirectReference</signatureKeyIdentifier>
    <signatureParts>{Element}{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Timestamp;{Element}{}Body</signatureParts>

    注意,签名部分中Body的namespace是空的,而没有设置为http://schemas.xmlsoap.org/soap/envelope/(SOAP 1.1对应的ns)或者http://www.w3.org/2003/05/soap-envelope(对应SOAP 1.2),这是为了兼容SOAP 1.1和1.2两个版本,若指定了ns,则只能兼容其一,.Net、Java客户端调用默认都使用SOAP 1.1版,而WSF/PHP则默认使用1.2版本,这样就无法做到各语言的完全
    服务端搞定之后,我们就可以来进行.Net客户端的调试工作了,这里就不描述证书的准备工作了,直接开始;注意:以下的配置方案是在带有WSS支持的Web Service服务端特定配置基础上调试通过的,随着服务端配置的变化,客户端的配置和编码也会有一定的调整,所以以下配置并不保证对所有服务端配置都联调成功;

    WSE 2.0配置(VS 2003)

    1)右键单击工程,选择WSE Settings 2.0 ...开始设置,若在VS 2005环境种使用WSE 2.0,则菜单中没有该项,需要单独打开WSE的Configuration Tool进行设置;
    2)在Settings Tool中General页中选中Enable this projects for Web Services Enhancements;
    3)Policy页中选中Enable Policy,点击Add ...按钮新建Policy配置文件;
    4)Add or Rename Endpoint URI窗口中保留默认值<DefaultEndpoint>,点击OK;
    5)保持Next,到Message Settings窗口中对Request Message、Response Message都选择Require Signatures,因为我们只需要进行签名验证,而不需要加密;
    6)Next到Client Certificate窗口中,选择客户端签名需要的私钥证书;
    7)Trusted Server Certificate窗口中,选择验证服务端签名需要的公钥证书;
    8)保存退出,会在工程中出现policyCache.config配置文件,打开;
    9)找到response对应的Policy配置项中的wsp:MessagePredicate和wssp:MessageParts,删除其中多余的配置项,只保留wsp:Body();
    10)添加Web Reference,然后修改Reference.cs文件中继承的父类,由System.Web.Services.Protocols.SoapHttpClientProtocol修改为Microsoft.Web.Services2.WebServicesClientProtocol;对于此点可能在vs2003环境下面是不需要的,我只在VS 2005环境下面测试过,VS 2005下面是必须的;
    11)写ws调用类并运行;
    和我们以前WSE 2.0的配置相比,主要变化在于现在不需要选中Use RFC2380选项了;

    WSE 3.0配置(VS 2005)

    和WSE 2.0配置一样,完全借助于Configuration Tool,注意以下点:
    1)可以先配置Policy再添加Web Reference引用,这样产生的代理类会自动继承Microsoft.Web.Services3.WebServicesClientProtocol;
    2)调用代码中需要自己设置要使用的policy名称;
    3)Security页中X.509 Certificate Settings中的选项都保持默认值,除了Store Location;
    4)新建Policy时Message Protection步骤中选择要注意顺序,顺序的不同会产生很不一样的效果,结果会导致接口调用步成功,最傻瓜的操作如下图所示:
    这应该是.Net下面调用带有WSS支持的Web Service最傻瓜的操作了,全向导性配置,只需要三行代码即可调用WS;

    WCF配置(VS 2008)

    WCF的配置又复杂一些了,因为WCF整合了许多其他的东西,而不仅仅是一个支持WS-Security的工具,配置文件中各项的选择性也非常的大,取值范围非常的广,这样反而让开发人员在配置的时候感觉到盲目;WCF也有自己的配置工具WCF Service Configuration Editor,可以从“工具”菜单栏或者开始菜单中加载;这里就不帖具体每项的配置了,因为配置工具中没有向导;直接帖一个可用的配置文件: 

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <!-- If you wan to turn on logging, uncomment the "sources" section below, and set the correct log files in sharedListeners section. -->
        <system.diagnostics>
            <sharedListeners>
              <!-- TODO: Please fix the log file name here! -->
                <add initializeData="F:TempTracesapp_messages_aliclient.svclog"
                    type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
                    name="ServiceModelMessageLoggingListener" traceOutputOptions="Timestamp">
                    <filter type="" />
                </add>
              <!-- TODO: Please fix the log file name here! -->
                <add initializeData="F:TempTracesapp_tracelog_aliclient.svclog"
                    type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
                    name="ServiceModelTraceListener" traceOutputOptions="Timestamp">
                    <filter type="" />
                </add>
            </sharedListeners>
        </system.diagnostics>
        <system.serviceModel>
          <!-- To turn on message logging, set these flags to "true" -->
            <diagnostics>
                <messageLogging logEntireMessage="false" logMalformedMessages="false"
                    logMessagesAtTransportLevel="false" />
            </diagnostics>
            <bindings>
                <customBinding>
                    <binding name="Soap11CustomBinding">
                        <textMessageEncoding messageVersion="Soap11" />
                        <security defaultAlgorithmSuite="Basic128" allowSerializedSigningTokenOnReply="true"
                            authenticationMode="MutualCertificate" requireDerivedKeys="false"
                            securityHeaderLayout="Lax" includeTimestamp="true" keyEntropyMode="CombinedEntropy"
                            messageProtectionOrder="SignBeforeEncrypt" messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
                            requireSecurityContextCancellation="false">
                            <secureConversationBootstrap />
                        </security>
                        <httpTransport />
                    </binding>
                </customBinding>
            </bindings>
          <behaviors>
            <endpointBehaviors>
              <behavior name="NewBehavior">
                <clientCredentials>
                  <clientCertificate findValue="CN=5" storeLocation="CurrentUser"
                    storeName="My" x509FindType="FindBySubjectDistinguishedName" />
                  <serviceCertificate>
                    <defaultCertificate findValue="CN=alisoft" storeLocation="CurrentUser"
                      storeName="My" x509FindType="FindBySubjectDistinguishedName" />
                    <authentication customCertificateValidatorType="" certificateValidationMode="PeerOrChainTrust" />
                  </serviceCertificate>
                  <issuedToken cacheIssuedTokens="false" />
                </clientCredentials>
              </behavior>
            </endpointBehaviors>
          </behaviors>
            <client>
                <!--121.0.18.160-->
                <endpoint address="http://localhost:1688/webservice/AppConsumeService"
                    behaviorConfiguration="NewBehavior" binding="customBinding"
                    bindingConfiguration="Soap11CustomBinding" contract="ServiceReference1.AppConsumeServicePortType"
                    name="Soap11CustomBindingPort">
                    <identity>
                        <dns value="alisoft" />
                        <certificateReference x509FindType="FindBySubjectName" />
                    </identity>
                </endpoint>
            </client>
        </system.serviceModel>
    </configuration>

    客户端调用代码为:

    ServiceReference1.AppConsumeServicePortTypeClient c = new ServiceReference1.AppConsumeServicePortTypeClient("Soap11CustomBindingPort");
    //设置保护级别为签名
    c.Endpoint.Contract.ProtectionLevel = System.Net.Security.ProtectionLevel.Sign;
    string bal = c.checkBalance("85", "afc376c9-d14b-4820-bc77-e22878fa8ce3", 11);
    Console.WriteLine("bal is:" + bal);

    至于WCF配置中的细项我也还没有深入探讨过,以上的配置都是基于微软亚洲研究院联调成功的配置之上的;

  • 相关阅读:
    IIS和tomcat共用80端口
    CYQ.Data V5 从入门到放弃ORM系列:教程
    C#中==与Equals方法的区别
    一个简单得不能再简单的“ORM”了
    msbuild ConfuserEx.Build 加密
    C#生成注册码
    从多个XML文档中读取数据用于显示webapi帮助文档
    ASP.NET MVC SSO 单点登录设计与实现
    ASP.NET MVC Bootstrap极速开发框架
    Nodejs初阶之express
  • 原文地址:https://www.cnblogs.com/yf2011/p/5465558.html
Copyright © 2020-2023  润新知