WebServiceTransportException: неавторизованный [401] в Spring-WS

Мы изо всех сил пытаемся настроить наше веб-приложение так, чтобы оно могло подключаться к веб-службам через Spring WS. Мы попытались использовать пример из документации клиентской Spring-WS, но в итоге получили исключение WebServiceTransportException. Конфигурация XML выглядит так:

<bean id = "webServiceTemplate" class = "org.springframework.ws.client.core.WebServiceTemplate">
    <constructor-arg ref = "messageFactory"/>
    <property name = "messageSender">
        <bean class = "org.springframework.ws.transport.http.CommonsHttpMessageSender">
            <property name = "credentials">
                <bean class = "org.apache.commons.httpclient.UsernamePasswordCredentials">
                    <constructor-arg value = "john"/>
                    <constructor-arg value = "secret"/>
                </bean>
            </property>
        </bean>
    </property>
</bean>

Нам удалось настроить приложение программно, но эту конфигурацию невозможно «перенести» в конфигурацию Spring XML, поскольку некоторые сеттеры не использовали формат, ожидаемый Spring. (HttpState.setCredentials (...) принимает два параметра). Конфигурация была взята из другого клиентского кода Spring-WS в компании.

Это конфигурация, которая работает:

 public List<String> getAll() {
    List<String> carTypes = new ArrayList<String>();

    try {
        Source source = new ResourceSource(request);
        JDOMResult result = new JDOMResult();


        SaajSoapMessageFactory soapMessageFactory = new SaajSoapMessageFactory(MessageFactory.newInstance());

        WebServiceTemplate template = new WebServiceTemplate(soapMessageFactory);

        HttpClientParams clientParams = new HttpClientParams();
        clientParams.setSoTimeout(60000);
        clientParams.setConnectionManagerTimeout(60000);
        clientParams.setAuthenticationPreemptive(true);

        HttpClient client = new HttpClient(clientParams);
        client.getState().setCredentials(AuthScope.ANY,
                new UsernamePasswordCredentials("username", "password"));

        CommonsHttpMessageSender messageSender = new CommonsHttpMessageSender(client);

        template.setMessageSender(messageSender);
        template.sendSourceAndReceiveToResult(SERVICE_URI,
                source, result);

        // Handle the XML

    } catch (IOException e) {
        throw new RuntimeException(e);
    } catch (SOAPException e) {
        throw new RuntimeException(e);
    }

    return carTypes;
}

Кто-нибудь знает, как решить мою проблему? В каждом учебном пособии, которое я видел, указана первая конфигурация. Кажется, что когда я устанавливаю учетные данные для объекта messageSender, они просто игнорируются ...

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
7 750
4

Ответы 4

Как вы их различите:

<constructor-arg value = "john"/>
<constructor-arg value = "secret"/>

попробуйте заменить его на это:

<property name = "userName" value = "john" />
<property name = "password" value = "secret" />

Надеюсь, это поможет.

Если указано, как указано выше, Spring различает аргументы конструктора по порядку появления. Обозначение <property ...> будет переключаться только между установкой атрибутов конструктором и установкой их с помощью средства доступа. Боюсь, это ничего не изменит.

rowing-ghoul 03.05.2013 18:27

Переопределите HttpClient с помощью конструктора, который принимает параметры и подключается к Spring с помощью constructor-args

public MyHttpClient(HttpClientParams params, UsernamePasswordCredentials usernamePasswordCredentials) {
        super(params);        
        getState().setCredentials(AuthScope.ANY, usernamePasswordCredentials);
    }

Если вы используете defaultHttpClient, как в своем примере, используйте метод afterPropertiesSet в своем HTTPMessageSender, и это должно решить вашу проблему, правильно применив учетные данные.

Сначала мы устанавливали учетные данные в нашем проекте следующим образом:

<bean id = "authenticationEnabledCommonsHttpMessageSender" parent = "commonsHttpMessageSender"
    p:credentials-ref = "clientCredentials" lazy-init = "true" />
<bean id = "clientCredentials"
    class = "org.apache.commons.httpclient.UsernamePasswordCredentials"
    c:userName = "${clientCredentials.userName}"
    c:password = "${clientCredentials.password}"
    lazy-init = "true" />

Это наша опция включения критических данных. При настройке таких учетных данных возникла проблема. Если сервер, который мы отправляем сообщение (имеет Axis impl), не имеет учетных данных для имени пользователя и пароля, мы получаем исключение «Неавторизованный». Потому что, когда мы отслеживаем TCPMon, мы обнаружили, что строка «username: password:» была отправлена, так как вы можете видеть, что имя пользователя и пароль не имеют значения.

После этого мы устанавливаем такие учетные данные:

public Message sendRequest(OutgoingRequest message, MessageHeaders headers,
                        EndpointInfoProvider endpointInfoProvider,
                        WebServiceMessageCallback requestCallback){
    Assert.notNull(endpointInfoProvider, "Destination provider is required!");
    final Credentials credentials = endpointInfoProvider.getCredentials();
    URI destinationUri = endpointInfoProvider.getDestination();
    for (WebServiceMessageSender messageSender : webServiceTemplate.getMessageSenders()) {
        if (messageSender instanceof CommonsHttpMessageSender) {
            HttpClient httpClient = ((CommonsHttpMessageSender) messageSender).getHttpClient();
            httpClient.getState().setCredentials(
                    new AuthScope(destinationUri.getHost(),
                            destinationUri.getPort(), AuthScope.ANY_REALM,
                            AuthScope.ANY_SCHEME), credentials
            );
            httpClient.getParams().setAuthenticationPreemptive(true);
            ((CommonsHttpMessageSender) messageSender)
                    .setConnectionTimeout(endpointInfoProvider
                            .getTimeOutDuration());
        }
    }

И метод getCredentials:

@Override
public Credentials getCredentials(){
    if (credentials != null) {
        return credentials;
    }
    String username = parameterService.usernameFor(getServiceName());
    String password = parameterService.passwordFor(getServiceName());
    if (username == null && password == null) {
        return null;
    }
    credentials = new UsernamePasswordCredentials(username, password);
    return credentials;
}

Другие вопросы по теме