使用SOAP WS返回错误401未经授权



我正在尝试使用spring-ws使用SOAP Web服务。我能够从SOAP UI成功地使用此web服务。然而,我收到了一个未经授权的异常:

org.springframework.ws.client.WebServiceTransportException: Unauthorized [401]
    at org.springframework.ws.client.core.WebServiceTemplate.handleError(WebServiceTemplate.java:699)

如何成功进行身份验证?

我的代码如下:

WebServiceTemplate配置:

@Bean
    public WebServiceTemplate webServiceTemplate(Jaxb2Marshaller marshaller){
        WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
        webServiceTemplate.setDefaultUri("http://ultron.illovo.net:9704/AdminService");
        webServiceTemplate.setMarshaller(marshaller);
        webServiceTemplate.setUnmarshaller(marshaller);
        Credentials credentials = new UsernamePasswordCredentials("biqa", "welcome1");
        HttpComponentsMessageSender messageSender = new HttpComponentsMessageSender();
        messageSender.setCredentials(credentials);
        messageSender.setReadTimeout(5000);
        messageSender.setConnectionTimeout(5000);
        webServiceTemplate.setMessageSender(messageSender);
        return webServiceTemplate;
    }

客户端:

@Autowired
WebServiceTemplate webServiceTemplate;
public CallProcedureWithResultsResponse callProcedureWithResults(String procedureName){
    CallProcedureWithResults request = new CallProcedureWithResults();
    request.setProcedureName(procedureName);
    log.info("Calling procedure " + procedureName);
    CallProcedureWithResultsResponse response = (CallProcedureWithResultsResponse) webServiceTemplate.marshalSendAndReceive("http://ultron.illovo.net:9704/AdminService/AdminService", request);
    return response;
}

JUnit测试

@Test
    public void testWebService(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ObieeConfiguration.class);
        ObieeClient client = context.getBean(ObieeClient.class);
        CallProcedureWithResultsResponse response = client.callProcedureWithResults("GetOBISVersion()");
        client.printResponse(response);
        context.close();
    }

我通过以下操作解决了这个问题:

创建HttpUrlConnectionMessageSender的子类,如下所示:

public class WebServiceMessageSenderWithAuth extends HttpUrlConnectionMessageSender {
    String user;
    String password;
    public WebServiceMessageSenderWithAuth(String user, String password) {
        this.user = user;
        this.password = password;
    }
    @Override
     protected void prepareConnection(HttpURLConnection connection) throws IOException { 
        BASE64Encoder enc = new BASE64Encoder(); 
        String userpassword = user+":"+password;
        String encodedAuthorization = enc.encode( userpassword.getBytes() ); 
        connection.setRequestProperty("Authorization", "Basic " + encodedAuthorization); 
        super.prepareConnection(connection); 
    } 
}

我的客户定义如下:

public class ObieeClient extends WebServiceGatewaySupport {
    private static final Logger log = LoggerFactory.getLogger(ObieeClient.class);
    public CallProcedureWithResultsResponse callProcedureWithResults(String procedureName, String webServiceURL){
        CallProcedureWithResults request = new CallProcedureWithResults();
        request.setProcedureName(procedureName);
        log.info("Calling procedure " + procedureName);
        CallProcedureWithResultsResponse response = (CallProcedureWithResultsResponse) ((JAXBElement) getWebServiceTemplate().marshalSendAndReceive(webServiceURL, request)).getValue();
        return response;
    }
}

最后,客户端被配置为通过设置消息发送者来使用凭据:

     Jaxb2Marshaller marshaller = new Jaxb2Marshaller();            marshaller.setContextPath("za.co.adaptit.smartdeployment.webservices.wsdl");
                //set up web service client
                ObieeClient client = new ObieeClient();
                client.setDefaultUri(host);
                client.setMarshaller(marshaller);
                client.setUnmarshaller(marshaller);
                client.setMessageSender(new WebServiceMessageSenderWithAuth("user", "password"));
response = client.callProcedureWithResults("NQSModifyMetadata('" + obieeObjectsXML +"')", server.getHost());

希望这能有所帮助。

我遇到了同样的问题,并通过定义一个具有凭据的MessageSender,然后将其设置到客户端来解决。我不必创建自定义MessageSender。

@Bean
public WebServiceMessageSender messageSender(Credentials credentials) throws Exception{
    HttpComponentsMessageSender messageSender = new HttpComponentsMessageSender();
    messageSender.setCredentials(credentials);
    return messageSender;
}
@Bean
public Credentials credentials(){
    UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(USERNAME, PASSWORD);
    return credentials;
}

使用HttpsUrlConnectionMessageSender进行安全的Https连接。这是spring-ws支持依赖项的一部分。此外,您可以使用HttpsUrlConnectionMessageSender绕过各种证书问题,比如证书通用名称不匹配。

不要使用BASE64Encoder,它是sun.misc jar的类,不太安全。使用java 1.8中存在的java util的Base64,对于低于java 1.8 的java版本,使用apache的Base64

public class WebServiceMessageSenderWithAuth extends HttpsUrlConnectionMessageSender {
String user;
String password;
public WebServiceMessageSenderWithAuth(String user, String password) {
    this.user = user;
    this.password = password;
   }
@Override
 protected void prepareConnection(HttpURLConnection connection) throws IOException { 
    String userpassword = user+":"+password;
    String encodedAuthorization = Base64.encode( userpassword.getBytes() ); 
    connection.setRequestProperty("Authorization", "Basic " + encodedAuthorization); 
    //set various properties by using reference of connection according to your requirement
   } 
}

MessageSender必须是一个bean,因为它在其afterPropertiesSet方法中为底层HttpClient设置凭据,只有当它是bean时,Spring才会自动调用该方法。看见https://github.com/spring-projects/spring-ws/blob/02cf3b7e2107d5ba728e9210cb705f31931c702a/spring-ws-core/src/main/java/org/springframework/ws/transport/http/HttpComponentsMessageSender.java#L221-L227

因此,在您的情况下,这种情况永远不会发生,并且您最终会得到一个没有凭据的HttpClient实例,从而正确地生成401。

其他方式是:

  • 手动调用该方法
  • 使用凭据创建自己的HttpClient并将其设置为HttpComponentsMessageSender

但我只是将消息发送者定义为bean。

最新更新