webservice复杂加密签名(2)java调用

依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-ws</artifactId>
    <version>1.4.7.RELEASE</version>
</dependency>
<dependency>
    <groupId>wsdl4j</groupId>
    <artifactId>wsdl4j</artifactId>
</dependency>

WSDL转java

在这里插入图片描述

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <includeSystemScope>true</includeSystemScope>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.jvnet.jaxb2.maven2</groupId>
            <artifactId>maven-jaxb2-plugin</artifactId>
            <version>0.13.2</version>
            <executions>
                <execution>
                    <goals>
                        <goal>generate</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <schemaLanguage>WSDL</schemaLanguage>
                <generateDirectory>${basedir}/src/main/java</generateDirectory>
                <schemas>
                    <schema>
                        <fileset>
                            <directory>${basedir}/src/main/resources/wsdl</directory>
                            <includes>
                                <include>*.wsdl</include>
                                <include>*.wsd</include>
                            </includes>
                        </fileset>
                    </schema>
                </schemas>
            </configuration>
        </plugin>
    </plugins>
</build>
mvn org.jvnet.jaxb2.maven2:maven-jaxb2-plugin:0.13.2:generate

在这里插入图片描述

HTTPS签名

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.ws.transport.http.ClientHttpRequestMessageSender;

import javax.net.ssl.SSLContext;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.KeyStore;

@Slf4j
@Configuration
public class SoapConfig {

    @Value("${mastercard.keystore.client.path}")
    private String clientKeystorePath;
    @Value("${mastercard.keystore.client.password}")
    private String clientPassword;

    @Bean
    public WebServiceMessageSender webServiceMessageSender() throws Exception {
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        byte[] keystoreBytes;
        try (InputStream inputStream = resolver.getResource(clientKeystorePath).getInputStream()) {
            keystoreBytes = IOUtils.toByteArray(inputStream);
        } catch (Exception e) {
            log.error("https秘钥文件client.jks读取异常, keystore: {}", clientKeystorePath);
            throw e;
        }

        KeyStore keystore = KeyStore.getInstance("PKCS12");
        keystore.load(new ByteArrayInputStream(keystoreBytes), clientPassword.toCharArray());

        SSLContext sslContext = SSLContexts.custom()
                .loadKeyMaterial(keystore, clientPassword.toCharArray())
                .build();
        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
        CloseableHttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(csf)
                .build();
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient);
        requestFactory.setConnectTimeout(10_000);
        requestFactory.setReadTimeout(10_000);
        ClientHttpRequestMessageSender messageSender = new ClientHttpRequestMessageSender();
        messageSender.setRequestFactory(requestFactory);
        return messageSender;
    }

}

报文签名

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Component;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.soap.saaj.SaajSoapMessage;

import javax.xml.crypto.dom.DOMStructure;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.soap.*;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Provider;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Base64;

@Slf4j
@Component
public class SoapSignService {

    private final KeyStore keystore;
    private final String password;
    private final String keystoreAlias;

    @Value("${mastercard.system.institutionName}")
    private String institutionName;

    @Autowired
    public SoapSignService(@Value("${mastercard.keystore.sign.path}") String path,
                           @Value("${mastercard.keystore.sign.password}") String password,
                           @Value("${mastercard.keystore.sign.alias}") String keystoreAlias) throws Exception {
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        byte[] keystoreBytes;
        try (InputStream inputStream = resolver.getResource(path).getInputStream()) {
            keystoreBytes = IOUtils.toByteArray(inputStream);
        } catch (Exception e) {
            log.error("签名秘钥文件signing.jks读取异常, keystore: {}", path);
            throw e;
        }

        this.keystore = KeyStore.getInstance("PKCS12");
        this.keystore.load(new ByteArrayInputStream(keystoreBytes), password.toCharArray());
        this.password = password;
        this.keystoreAlias = keystoreAlias;
    }

    private PrivateKey getKeyFormCert() throws Exception {
        return (PrivateKey) keystore.getKey(keystoreAlias, password.toCharArray());
    }

    private java.security.cert.Certificate getCertificate() throws Exception {
        return keystore.getCertificate(keystoreAlias);
    }

    public void sign(WebServiceMessage message) {
        sign("", message);
    }

    public void sign(String appId, WebServiceMessage message) {
        this.sign(appId, ((SaajSoapMessage) message).getSaajMessage());
    }

    public void sign(String appId, SOAPMessage soapMessage) {
        try {
            SOAPEnvelope soapEnvelope = soapMessage.getSOAPPart().getEnvelope();
            soapEnvelope.setPrefix("soapenv");
            soapEnvelope.removeNamespaceDeclaration("SOAP-ENV");
            soapEnvelope.addNamespaceDeclaration("com", "http://common.ws.mcrewards.mastercard.com/");

            SOAPHeader header = soapMessage.getSOAPHeader();
            header.setPrefix("soapenv");
            SOAPElement identity = header.addChildElement("identity", "com");
            identity.addAttribute(soapEnvelope.createName("Id", "wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"), "IDENTITY");

            SOAPElement appID = identity.addChildElement("appID");
            appID.addTextNode(appId);
            SOAPElement institutionName = identity.addChildElement("institutionName");
            institutionName.addTextNode(this.institutionName);

            SOAPBody soapBody = soapMessage.getSOAPBody();
            soapBody.setPrefix("soapenv");
            soapBody.addAttribute(soapEnvelope.createName("Id", "wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"), "Body");

            signSOAPMessage(soapMessage);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    private void signSOAPMessage(SOAPMessage soapMessage) throws Exception {
        // Create the security element
        SOAPElement soapHeader = soapMessage.getSOAPHeader();
        SOAPElement securityElement = soapHeader.addChildElement("Security", "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
        securityElement.addNamespaceDeclaration("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

        // (i) Extract the certificate from the .p12 file.
        java.security.cert.Certificate cert = getCertificate();

        // (ii) Add Binary Security Token. The base64 encoded value of the ROS digital certificate.
        SOAPElement binarySecurityToken = addBinarySecurityToken(securityElement, soapMessage, cert);

        //(iii) Add Timestamp element
        SOAPElement timestamp = addTimestamp(securityElement, soapMessage);

        // (iv) Add signature element
        // Get private key from ROS digital certificate
        PrivateKey key = getKeyFormCert();
        SOAPElement securityTokenReference = addSecurityToken(securityElement);
        addSignature(securityElement, key, securityTokenReference, soapMessage.getSOAPBody(), timestamp, binarySecurityToken);
    }

    private SOAPElement addSecurityToken(SOAPElement signature) throws SOAPException {
        SOAPElement securityTokenReference = signature.addChildElement("SecurityTokenReference", "wsse");
        SOAPElement reference = securityTokenReference.addChildElement("Reference", "wsse");
        reference.setAttribute("URI", "#X509Token");
        return securityTokenReference;
    }

    private void addSignature(SOAPElement signatureElement, PrivateKey privateKey, SOAPElement securityTokenReference, SOAPBody soapBody, SOAPElement timestamp, SOAPElement binarySecurityToken) throws Exception {
        String providerName = System.getProperty("jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI");
        XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM", (Provider) Class.forName(providerName).newInstance());

        //Digest method
        javax.xml.crypto.dsig.DigestMethod digestMethod = xmlSignatureFactory.newDigestMethod("http://www.w3.org/2001/04/xmlenc#sha512", null);
        ArrayList<Transform> transformList = new ArrayList<>();

        //Transform
        Transform envTransform = xmlSignatureFactory.newTransform("http://www.w3.org/2001/10/xml-exc-c14n#", (TransformParameterSpec) null);
        transformList.add(envTransform);

        //References
        ArrayList<Reference> referenceList = new ArrayList<>();
        Reference x509 = xmlSignatureFactory.newReference("#X509Token", digestMethod, transformList, null, null);
        Reference refTS = xmlSignatureFactory.newReference("#TS", digestMethod, transformList, null, null);
        Reference refBody = xmlSignatureFactory.newReference("#Body", digestMethod, transformList, null, null);
        Reference header = xmlSignatureFactory.newReference("#IDENTITY", digestMethod, transformList, null, null);
        referenceList.add(x509);
        referenceList.add(refTS);
        referenceList.add(refBody);
        referenceList.add(header);

        javax.xml.crypto.dsig.CanonicalizationMethod cm = xmlSignatureFactory.newCanonicalizationMethod("http://www.w3.org/2001/10/xml-exc-c14n#", (C14NMethodParameterSpec) null);
        javax.xml.crypto.dsig.SignatureMethod sm = xmlSignatureFactory.newSignatureMethod("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512", null);
        SignedInfo signedInfo = xmlSignatureFactory.newSignedInfo(cm, sm, referenceList);


        DOMSignContext signContext = new DOMSignContext(privateKey, signatureElement);
        signContext.setDefaultNamespacePrefix("ds");
        signContext.putNamespacePrefix("http://www.w3.org/2000/09/xmldsig#", "ds");

        //These are required for new Java versions
        signContext.setIdAttributeNS(soapBody, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "Id");
        signContext.setIdAttributeNS(timestamp, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "Id");
        signContext.setIdAttributeNS(binarySecurityToken, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "Id");

        KeyInfoFactory keyFactory = KeyInfoFactory.getInstance();
        DOMStructure domKeyInfo = new DOMStructure(securityTokenReference);
        javax.xml.crypto.dsig.keyinfo.KeyInfo keyInfo = keyFactory.newKeyInfo(java.util.Collections.singletonList(domKeyInfo));
        javax.xml.crypto.dsig.XMLSignature signature = xmlSignatureFactory.newXMLSignature(signedInfo, keyInfo);
        signContext.setBaseURI("");
        signature.sign(signContext);
    }

    private SOAPElement addTimestamp(SOAPElement securityElement, SOAPMessage soapMessage) throws SOAPException {
        SOAPElement timestamp = securityElement.addChildElement("Timestamp", "wsu");
        SOAPEnvelope soapEnvelope = soapMessage.getSOAPPart().getEnvelope();
        timestamp.addAttribute(soapEnvelope.createName("Id", "wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"), "TS");

        String DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ssX";
        DateTimeFormatter timeStampFormatter = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN);
        ZonedDateTime zonedDateTime = ZonedDateTime.now();
        timestamp.addChildElement("Created", "wsu").setValue(timeStampFormatter.format(zonedDateTime.toInstant().atZone(ZoneId.of("UTC"))));
        timestamp.addChildElement("Expires", "wsu").setValue(timeStampFormatter.format(zonedDateTime.plusSeconds(60).toInstant().atZone(ZoneId.of("UTC"))));
        return timestamp;
    }

    private SOAPElement addBinarySecurityToken(SOAPElement securityElement, SOAPMessage soapMessage, java.security.cert.Certificate cert) throws Exception {
        byte[] certByte = cert.getEncoded();
        SOAPElement binarySecurityToken = securityElement.addChildElement("BinarySecurityToken", "wsse");

        binarySecurityToken.setAttribute("ValueType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3");
        binarySecurityToken.setAttribute("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
        SOAPEnvelope soapEnvelope = soapMessage.getSOAPPart().getEnvelope();

        binarySecurityToken.addAttribute(soapEnvelope.createName("Id", "wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"), "X509Token");
        binarySecurityToken.addTextNode(Base64.getEncoder().encodeToString(certByte));
        return binarySecurityToken;
    }

}

调用层

import com.mastercard.mcrewards.ws.common.EmptyElement;
import com.mastercard.mcrewards.ws.diagnostic.ApplicationStatus;
import com.mastercard.mcrewards.ws.diagnostic.CurrentVersion;
import com.mastercard.mcrewards.ws.diagnostic.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.stereotype.Service;
import org.springframework.ws.client.core.WebServiceMessageCallback;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
import org.springframework.ws.transport.WebServiceMessageSender;

import javax.xml.bind.JAXBElement;

@Service
public class SoapDiagnosticService extends WebServiceGatewaySupport {

    private static final ObjectFactory factory = new com.mastercard.mcrewards.ws.diagnostic.ObjectFactory();
    private static final String packagePath = "com.mastercard.mcrewards.ws.diagnostic";

    private SoapSignService soapSignService;

    @Autowired
    public SoapDiagnosticService(WebServiceMessageSender messageSender,
                                 SoapSignService soapSignService,
                                 @Value("${mastercard.service.diagnosticServiceLink}") String link) {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setContextPath(packagePath);
        this.setDefaultUri(link);
        this.setMarshaller(marshaller);
        this.setUnmarshaller(marshaller);
        this.setMessageSender(messageSender);
        this.soapSignService = soapSignService;
    }

    public String doEcho(String request) {
        JAXBElement<String> source = factory.createDoEcho(request);
        WebServiceMessageCallback wsCallback = message -> soapSignService.sign(message);
        JAXBElement response = (JAXBElement) getWebServiceTemplate().marshalSendAndReceive(source, wsCallback);
        return (String) response.getValue();
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
使用 Java Axis2 调用 WebService 接口可以通过以下步骤实现: 1. 下载并安装 Axis2。你可以从官方网站下载安装包,或者从 Maven 中央仓库获取依赖。 2. 创建一个 Java 项目,并将 Axis2 WebService 客户端库添加到项目依赖中。 3. 根据 WebService WSDL 文件生成客户端代码。你可以使用 Axis2 自带的 wsdl2java 工具,在命令行中运行以下命令: ``` wsdl2java -uri <wsdl-url> -p <package-name> -d <output-directory> ``` 其中,`<wsdl-url>` 是 WebService 的 WSDL 文件地址,`<package-name>` 是你想要生成代码的 Java 包名,`<output-directory>` 是生成代码的输出目录。 4. 在你的 Java 代码中创建 WebService 客户端对象,并调用 WebService 方法。例如: ``` MyWebServiceStub stub = new MyWebServiceStub(); MyWebServiceStub.MyWebServiceRequest request = new MyWebServiceStub.MyWebServiceRequest(); request.setParameter("value"); MyWebServiceStub.MyWebServiceResponse response = stub.myWebServiceMethod(request); System.out.println(response.getResult()); ``` 这里的 `MyWebServiceStub` 是在第三步中生成的客户端代码中的类名,`myWebServiceMethod` 是 WebService 的方法名,`MyWebServiceRequest` 和 `MyWebServiceResponse` 是方法的请求和响应对象。 以上就是使用 Java Axis2 调用 WebService 接口的基本步骤。需要注意的是,在实际项目中,你可能还需要处理异常、设置 WebService 的认证和安全等问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值