如何在 jax-ws 请求中添加安全性 header
how to add security header in jax-ws request
我正在使用 apache cxf 创建一个 jax-ws 客户端。
我正在为 spring cotext 配置而苦苦挣扎。
我只需要将此 header 添加到我的 soap 请求中:
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken wsu:Id="usernametoken">
<wsse:Username>login</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
我有三个参数:usernametoken, password, login.
<jaxws:client id="***" name="***"
endpointName="***"
serviceName="***"
address="***"
serviceClass="***"
username="***"
password="***"
xmlns:tns="***">
</jaxws:client>
上面的代码可以工作并发送 soap 消息,但没有安全性 header!
你能告诉我一些如何添加 header 的想法吗?
您需要使用 CXF 拦截器添加安全性 header。
所以您基本上需要定义一个新的拦截器 bean(WSS4JOutInterceptor 来自 cxf-security)并将正确的键值作为输入传递给它的构造函数:
<bean id="fooSecurityOutInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<constructor-arg>
<map>
[...]
</map>
</constructor-arg>
</bean>
请注意,这在 http://cxf.apache.org/docs/ws-security.html 中有记录,但您可能想查看 org.apache.ws.security.handler.WSHandlerConstants 的源代码以了解所有可能的键(在您的情况下,请查看 USERNAME_TOKEN, PASSWORD_TYPE...) 并将您的值注入此 bean 中的相应键。
然后,您只需将此 bean 作为 out 拦截器分配给您的 jaxws-client bean。
<jaxws:client id="***" name="***" endpointName="***" serviceName="***" address="***" serviceClass="***" xmlns:tns="***">
<jaxws:outInterceptors>
<ref bean="fooSecurityOutInterceptor" />
</jaxws:outInterceptors>
</jaxws:client>
这应该可以解决问题。
您可以添加第二个拦截器,例如 org.apache.cxf.interceptor.LoggingOutInterceptor 来检查是否添加了 header 来稍微调整键/值。
使用这个配置
<jaxws:client etc...>
<jaxws:outInterceptors>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken"/>
<entry key="user" value="login"/>
<entry key="passwordType" value="PasswordText"/>
<entry key="passwordCallbackRef" value-ref="myPasswordCallback"/>
</map>
</constructor-arg>
</bean>
</jaxws:outInterceptors>
</jaxws:client>
<bean id="myPasswordCallback" class="client.ClientPasswordCallback"/>
和这个class来管理密码
public class ClientPasswordCallback implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
if ("login".equals(pc.getIdentifier())) {
pc.setPassword("thepassword");
} // else {...} - can add more users, access DB, etc.
}
}
如果你喜欢Java代码,也可以
Client client = ClientProxy.getClient(port);
Endpoint cxfEndpoint = client.getEndpoint();
Map<String,Object> outProps = new HashMap<String,Object>();
outProps.put("action", "UsernameToken");
outProps.put("user", "login");
outProps.put("passwordType","PasswordText");
ClientPasswordCallback c = new ClientPasswordCallback();
outProps.put("passwordCallbackRef",c);
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
cxfEndpoint.getOutInterceptors().add(wssOut);
我正在使用 apache cxf 创建一个 jax-ws 客户端。 我正在为 spring cotext 配置而苦苦挣扎。 我只需要将此 header 添加到我的 soap 请求中:
<soapenv:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:UsernameToken wsu:Id="usernametoken">
<wsse:Username>login</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
我有三个参数:usernametoken, password, login.
<jaxws:client id="***" name="***"
endpointName="***"
serviceName="***"
address="***"
serviceClass="***"
username="***"
password="***"
xmlns:tns="***">
</jaxws:client>
上面的代码可以工作并发送 soap 消息,但没有安全性 header! 你能告诉我一些如何添加 header 的想法吗?
您需要使用 CXF 拦截器添加安全性 header。
所以您基本上需要定义一个新的拦截器 bean(WSS4JOutInterceptor 来自 cxf-security)并将正确的键值作为输入传递给它的构造函数:
<bean id="fooSecurityOutInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<constructor-arg>
<map>
[...]
</map>
</constructor-arg>
</bean>
请注意,这在 http://cxf.apache.org/docs/ws-security.html 中有记录,但您可能想查看 org.apache.ws.security.handler.WSHandlerConstants 的源代码以了解所有可能的键(在您的情况下,请查看 USERNAME_TOKEN, PASSWORD_TYPE...) 并将您的值注入此 bean 中的相应键。
然后,您只需将此 bean 作为 out 拦截器分配给您的 jaxws-client bean。
<jaxws:client id="***" name="***" endpointName="***" serviceName="***" address="***" serviceClass="***" xmlns:tns="***">
<jaxws:outInterceptors>
<ref bean="fooSecurityOutInterceptor" />
</jaxws:outInterceptors>
</jaxws:client>
这应该可以解决问题。 您可以添加第二个拦截器,例如 org.apache.cxf.interceptor.LoggingOutInterceptor 来检查是否添加了 header 来稍微调整键/值。
使用这个配置
<jaxws:client etc...>
<jaxws:outInterceptors>
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<constructor-arg>
<map>
<entry key="action" value="UsernameToken"/>
<entry key="user" value="login"/>
<entry key="passwordType" value="PasswordText"/>
<entry key="passwordCallbackRef" value-ref="myPasswordCallback"/>
</map>
</constructor-arg>
</bean>
</jaxws:outInterceptors>
</jaxws:client>
<bean id="myPasswordCallback" class="client.ClientPasswordCallback"/>
和这个class来管理密码
public class ClientPasswordCallback implements CallbackHandler {
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
if ("login".equals(pc.getIdentifier())) {
pc.setPassword("thepassword");
} // else {...} - can add more users, access DB, etc.
}
}
如果你喜欢Java代码,也可以
Client client = ClientProxy.getClient(port);
Endpoint cxfEndpoint = client.getEndpoint();
Map<String,Object> outProps = new HashMap<String,Object>();
outProps.put("action", "UsernameToken");
outProps.put("user", "login");
outProps.put("passwordType","PasswordText");
ClientPasswordCallback c = new ClientPasswordCallback();
outProps.put("passwordCallbackRef",c);
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
cxfEndpoint.getOutInterceptors().add(wssOut);