为认证添加SOAP头请求中的元素

5
我需要在我的新网络服务中加入一个身份验证头(即作为SOAP头请求的一部分)。该身份验证头将验证userId和密码细节。我必须验证身份验证的请求头详细信息以进行身份验证。如果经过身份验证,则将处理请求的SOAP正文,否则Web服务将向调用服务的客户端应用程序发送无效的身份验证消息。
我不知道如何创建一个包含某些元素(在我的情况下是身份验证元素,如userId和密码)的SOAP Header 的 Web服务。
通常,服务中公开的任何方法都将成为SOAP正文的一部分。因此,对于添加身份验证元素到SOAP Header,我感到困惑。
请帮忙。
谢谢!

有人可以看一下这个吗?https://stackoverflow.com/questions/43002576/soap-header-xmlnsds-on-each-element-for-xml-signature-generation - noob'88
2个回答

5

最近我写了一个类,将用户凭证添加到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>

但是它也可以在终端上实现。


是的,它来自javax.xml.ws.handler.soap包。我不知道它是否适用于JAX-RPC,我只在JAX-WS中使用过它。你应该尝试一下看看它是否可行 :) - Paulius Matulionis
1
这是一个关于JAX-RPC处理程序的IBM的链接,你应该阅读一下:http://www.ibm.com/developerworks/webservices/library/ws-tipjax2/index.html - Paulius Matulionis
如果您有一个处理程序并且可以将消息接收到该处理程序中,那么这意味着您可以对该消息进行任何操作。您只需要找出如何修改RPC样式的消息即可。以下是通过JAX-RPC完成此操作的示例:http://www.ibm.com/developerworks/xml/library/ws-tip-extend/index.html - Paulius Matulionis
是的,您需要在WSDL元素中声明minOccurs="1"。例如:<xsd:element type="tns:SomeElement" name="Element" minOccurs="1"/>。这将告诉堆栈此元素必须至少出现一次。 - Paulius Matulionis
1
如果您使用JAX-WS,有很多关于如何使其工作的文档。使用JAX-WS的解决方案是对您的Java参数进行注释:@XmlElement(required = true)。但我不知道JAX-RPC。 - Paulius Matulionis
显示剩余3条评论

0

我们只能从信封中获取头信息,而不能从SOAP消息中获取。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接