【问题标题】:Invoking soap web service via spring boot fails with Un-authorized 401 exception通过 Spring Boot 调用 Soap Web 服务失败,出现 Un-authorized 401 异常
【发布时间】:2020-02-02 17:23:20
【问题描述】:

我正在尝试通过 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。

我不知道如何传递此信息,因此将其设置为连接请求中的属性之一(在 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); 
   }

}

【问题讨论】:

  • 这里的任何帮助/指针都会有所帮助。有人可以帮忙吗?
  • 将 Rest 与 jwt 一起使用,浏览器会发送一个选项请求以检查是否接受了 Authorization 标头。您没有发布您的网络安全配置,但这可能是它在soap 工具上运行而不是在浏览器中运行的原因。会解释为什么你得到 401(身份验证错误)而不是 403(访问被拒绝)。曾经有过同样的休息问题,这就是我的解决方案。

标签: spring-boot soap jaxb


【解决方案1】:

您的 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;
    }

然后将其注入您的 Soap 客户端:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 2015-08-19
    • 2018-09-07
    • 1970-01-01
    • 2018-06-21
    • 1970-01-01
    相关资源
    最近更新 更多