Добавление элементов в запрос заголовка SOAP для аутентификации

Мне нужно включить заголовок аутентификации (т.е. как часть запроса заголовка SOAP) в мою новую веб-службу. Этот заголовок проверки подлинности проверит сведения об идентификаторе пользователя и пароле. Мне нужно проверить содержимое сведений заголовка запроса для аутентификации в моей веб-службе. В случае аутентификации будет обработано тело SOAP-запроса, в противном случае веб-служба отправит обратно сообщение о недопустимой аутентификации клиентскому приложению, вызывающему службу.

Я не могу понять, как создать веб-службу, в которой заголовок SOAP будет содержать некоторые элементы (в моем случае элементы аутентификации, такие как идентификатор пользователя и пароль).

Обычно любой метод, представленный в службе, является частью тела SOAP. Следовательно, непонятно, как продолжить добавление элементов аутентификации в заголовок SOAP.

Пожалуйста помоги

С уважением,


person user182944    schedule 05.09.2012    source источник
comment
Кто-нибудь может посмотреть на это? stackoverflow.com/questions/43002576/   -  person noob'88    schedule 31.03.2017


Ответы (2)


Недавно я написал класс, который добавляет учетные данные пользователя в заголовок SOAP. Для этого вам нужно создать класс, реализующий интерфейс SOAPHandler<SOAPMessageContext>. Например:

public class MyHandler implements SOAPHandler<SOAPMessageContext> {

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

    private String username;

    private String password;

    /**
     * Handles SOAP message. If SOAP header does not already exist, then method will created new SOAP header. The
     * username and password is added to the header as the credentials to authenticate user. If no user credentials is
     * specified every call to web service will fail.
     *
     * @param context SOAP message context to get SOAP message from
     * @return true
     */
    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        try {
            SOAPMessage message = context.getMessage();
            SOAPHeader header = message.getSOAPHeader();
            SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
            if (header == null) {
                header = envelope.addHeader();
            }
            QName qNameUserCredentials = new QName("https://your.target.namespace/", "UserCredentials");
            SOAPHeaderElement userCredentials = header.addHeaderElement(qNameUserCredentials);

            QName qNameUsername = new QName("https://your.target.namespace/", "Username");
            SOAPHeaderElement username = header.addHeaderElement(qNameUsername );
            username.addTextNode(this.username);
            QName qNamePassword = new QName("https://your.target.namespace/", "Password");
            SOAPHeaderElement password = header.addHeaderElement(qNamePassword);
            password.addTextNode(this.password);

            userCredentials.addChildElement(username);
            userCredentials.addChildElement(password);

            message.saveChanges();
            //TODO: remove this writer when the testing is finished
            StringWriter writer = new StringWriter();
            message.writeTo(new StringOutputStream(writer));
            LOGGER.debug("SOAP message: \n" + writer.toString());
        } catch (SOAPException e) {
            LOGGER.error("Error occurred while adding credentials to SOAP header.", e);
        } catch (IOException e) {
            LOGGER.error("Error occurred while writing message to output stream.", e);
        }
        return true;
    }

    //TODO: remove this class after testing is finished
    private static class StringOutputStream extends OutputStream {

        private StringWriter writer;

        public StringOutputStream(StringWriter writer) {
            this.writer = writer;
        }

        @Override
        public void write(int b) throws IOException {
            writer.write(b);
        }
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        LOGGER.debug("handleFault has been invoked.");
        return true;
    }

    @Override
    public void close(MessageContext context) {
        LOGGER.debug("close has been invoked.");
    }

    @Override
    public Set<QName> getHeaders() {
        LOGGER.debug("getHeaders has been invoked.");
        return null;
    }

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

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

Обратите внимание, что я просто добавляю учетные данные в заголовок и возвращаю true. Вы делаете все, что хотите, со всем сообщением и возвращаете false, если что-то ожидаемое терпит неудачу.

Я реализовал этот клиент:

<bean id="soapHandler" class="your.package.MyHandler">
    <property name="username" value="testUser"/>
    <property name="password" value="testPassword"/>
</bean>

<jaxws:client "...">
    <jaxws:handlers>
        <ref bean="soapHandler"/>
    </jaxws:handlers>
</jaxws:client>

Но это также может быть реализовано на endpoint.

person Paulius Matulionis    schedule 06.09.2012
comment
Да, это происходит из пакета javax.xml.ws.handler.soap. Я не знаю, будет ли он работать с JAX-RPC, я использовал его только с JAX-WS. Вы должны попробовать и посмотреть, работает ли это :) - person Paulius Matulionis; 06.09.2012
comment
Вот ссылка, которую вы должны прочитать об обработчике JAX-RPC с IBM: ibm.com/developerworks/webservices/library/ws-tipjax2/ - person Paulius Matulionis; 06.09.2012
comment
Если у вас есть обработчик, и вы можете получить сообщение в этот обработчик, это означает, что вы можете делать с сообщением что угодно. Вам просто нужно выяснить, как изменить сообщение в стиле RPC. Вот примеры того, как это делается через JAX-RPC: ibm.com/developerworks/xml/library/ws-tip-extend/index.html - person Paulius Matulionis; 07.09.2012
comment
Я ничего не знаю о RPC, потому что я его не использовал. Я предлагаю вам взглянуть на Apache CXF: cxf. apache.org/docs/writing-a-service-with-spring.html. Это новейший стек веб-сервисов. Он основан на JAX-WS, но имеет много других функций, которые иногда очень полезны. - person Paulius Matulionis; 07.09.2012
comment
Да, вам нужно объявить minOccurs=1 в вашем элементе WSDL. Например: ‹xsd:element type=tns:SomeElement name=Element minOccurs=1/›. Это сообщит стеку, что этот элемент должен встречаться хотя бы один раз. - person Paulius Matulionis; 11.09.2012
comment
Какой подход вы используете? WSDL-First или Java-First? Если вы используете WSDL-first, мы должны добавить их вручную, потому что вы пишете свой WSDL вручную, а если Java-first, то я не знаю, вам нужно немного поискать. - person Paulius Matulionis; 11.09.2012
comment
Если вы будете использовать JAX-WS, есть много документации о том, как это сделать. Решение с JAX-WS состоит в том, чтобы аннотировать ваш параметр java: @XmlElement(required=true). Но я не знаю о JAX-RPC - person Paulius Matulionis; 11.09.2012
comment
В приведенном выше коде первым параметром для QName является пространство имен https, но для меня целевое пространство имен — http :( Откуда берется эта концепция https? Пожалуйста, помогите - person user182944; 15.09.2012

Мы можем получить заголовок только из конверта, а не из мыльного сообщения.

person Krishna Kumar Chourasiya    schedule 06.10.2015