spring-boot - 通过 Spring Boot 调用 SOAP Web 服务失败并出现未经授权的 401 异常

标签 spring-boot soap jaxb

我正在尝试通过 Spring Boot 应用程序调用安全的 SOAP Web 服务。

但是,当我尝试这样做时,尽管传递了所需的凭据,但我总是收到以下异常。

{
    "timestamp": "2020-02-02T17:17:09.081+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "Unauthorized [401]",
    "trace": "org.springframework.ws.client.WebServiceTransportException: Unauthorized [401]\n\tat org.springframework.ws.client.core.WebServiceTemplate.handleError(WebServiceTemplate.java:699)\n\tat org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:609)\n\tat org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:555)\n\tat org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:390)\n\tat org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:378)\n\tat com.app.oracle.doo.ominvoker.client.SoapClient.createOrder(SoapClient.java:30)\n\tat com.app.oracle.doo.ominvoker.controller.OrderImportController.createOrder(OrderImportController.java:55)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n\tat java.lang.reflect.Method.invoke(Method.java:498)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888)\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\n\tat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:660)\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:741)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1598)\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\n\tat java.lang.Thread.run(Thread.java:748)\n",
    "path": "/createOrder"
}

我已经能够通过提供相同的凭据来通过 SOAP 工具调用相同的 Web 服务。 我不确定传递 SOAP 头信息和调用 Web 服务的凭据的正确方法。

我引用了很多线程并找到了以下方法来实现它。然而,它对我来说仍然不起作用。

在这方面的任何帮助将不胜感激。

还有一点是,在通过soap工具调用服务时,我还将域信息设置为oracle/wss11_username_token_with_message_protection_client_policy。

我不知道如何传递此信息,因此将其设置为 Connection Request 中的属性之一(在 Authentication.java 文件中设置,如下所述)

谢谢

pom.xml

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web-services</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </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>
                    <args>
                        <arg>-XautoNameResolution</arg>
                    </args>
                    <generatePackage>com.app.oracle.doo.ominvoker.soap.api.orderimport</generatePackage>
                    <generateDirectory>${project.basedir}/src/main/java</generateDirectory>
                    <schemaDirectory>${project.basedir}/src/main/resources/wsdl</schemaDirectory>
                    <schemaIncludes>
                        <include>*.wsdl</include>
                    </schemaIncludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

SoapConfig.java

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;

import com.app.oracle.doo.ominvoker.client.SoapClient;

@Configuration
public class SoapConfig {

    @Bean
    public Jaxb2Marshaller marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setPackagesToScan("com.app.oracle.doo.ominvoker.soap.api.orderimport");
        return marshaller;
    }

    @Bean
    public SoapClient orderImportClient(Jaxb2Marshaller marshaller) {
        SoapClient client = new SoapClient();
        client.setDefaultUri("https://host:port/order/OrderServices");
        client.setMarshaller(marshaller);
        client.setUnmarshaller(marshaller);
        client.setMessageSender(new Authentication("Manager", "Welcome1"));
        return client;
    }

}

SoapClient.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.stereotype.Service;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;

import com.app.oracle.doo.ominvoker.soap.api.orderimport.CreateOrders;
import com.app.oracle.doo.ominvoker.soap.api.orderimport.CreateOrdersResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Service
public class SoapClient extends WebServiceGatewaySupport {

    private static final Logger LOGGER = LoggerFactory.getLogger(SoapClient.class);

    @Autowired
    private Jaxb2Marshaller marshaller;

    private WebServiceTemplate template;

    public CreateOrdersResponse createOrder(CreateOrders request) {
        template = new WebServiceTemplate(marshaller);
        return (CreateOrdersResponse) template.marshalSendAndReceive("https://host:port/order/OrderServices", request);
    }


}

身份验证.java

package com.app.oracle.doo.ominvoker.config;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.Base64;

import org.springframework.ws.transport.http.HttpUrlConnectionMessageSender;

public class Authentication extends HttpUrlConnectionMessageSender {

    private String username;

    private String password;

    public Authentication() {
    }

    public Authentication(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    protected void prepareConnection(HttpURLConnection connection) throws IOException { 
       String userpassword = username+":"+password;
       String encoded = Base64.getEncoder().withoutPadding().encodeToString(userpassword.getBytes());
       connection.setRequestProperty("Authorization", "Basic " + encoded);
       connection.setRequestProperty("domain", "oracle/wss11_username_token_with_message_protection_client_policy"); 
       super.prepareConnection(connection); 
   }

}

最佳答案

您的 WS 不是由 WS-Security 保护的吗? 而不是:HttpUrlConnectionMessageSender,您应该定义:org.springframework.ws.soap.security.wss4j2.Wss4jSecurityInterceptor

@Bean
    public Wss4jSecurityInterceptor securityInterceptor(){
        Wss4jSecurityInterceptor wss4jSecurityInterceptor = new Wss4jSecurityInterceptor();
        wss4jSecurityInterceptor.setSecurementActions("Timestamp UsernameToken");
        wss4jSecurityInterceptor.setSecurementUsername("Manager");
        wss4jSecurityInterceptor.setSecurementPassword("Welcome1");
        return wss4jSecurityInterceptor;
    }

然后将其注入(inject)到您的 Soap 客户端中:

    ClientInterceptor[] interceptors = new ClientInterceptor[] {securityInterceptor()};
    client.setInterceptors(interceptors);

关于spring-boot - 通过 Spring Boot 调用 SOAP Web 服务失败并出现未经授权的 401 异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60028677/

相关文章:

java - 使用 Cassandra 操作 Spring Boot 使用 Cassandra 准备语句

spring-boot - Azure 表和 Blob 测试

java - <bpmndi :BPMNShape> Is Missing for participant and lane element in xml when trying to create pool and lane from java source

java解码à的错误转换

java - 如何在 Spring Boot linux 中向类路径提供外部配置资源(数据库属性和 XML 文件)

java - 使用 log4j SMTPAppender 将日志发送到电子邮件

java - Spring Web 服务动态 wsdl 不为架构元素生成消息

node.js - Node Js SOAP 模块 - 超时选项

python - 对于 SalesForce API,这两个异常是什么意思?

java - 警告 "A web service endpoint could not be found"是什么?