在 WS 领域有一个很强悍的解决方案,名为 WS-Security
,它仅仅是一个规范,在 Java 业界里有一个很权威的实现,名为 WSS4J。
下面我将一步步让您学会,如何使用 Spring
+ CXF
+ WSS4J
实现一个安全可靠的 WS 调用框架。
本文是基于CXF与Spring集成,基础之上的,CXF与Spring集成请看:CXF系列之JAX-WS:与Spring3集成并在tomcat部署
其实您需要做也就是两件事情:
spring-cxf.xml配置:
首先定义了一个基于WSS4J的拦截器(WSS4JInInterceptor),然后通过package com.test.handler;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.wss4j.common.ext.WSPasswordCallback;
public class ServerPasswordCallback implements CallbackHandler {
private static final Map userMap = new HashMap();
static{
userMap.put("client", "clientpass");
userMap.put("server", "serverpass");
}
@Override
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback callback = (WSPasswordCallback) callbacks[0];
String clientUsername = callback.getIdentifier();
String serverPassword = userMap.get(clientUsername);
if (serverPassword != null) {
callback.setPassword(serverPassword);
}
}
}
可见,它实现了javax.security.auth.callback.CallbackHandler接口,这是JDK提供的用于安全认证的回调处理器接口,在代码中,提供了两个用户:server和client,用户名和密码都放在userMap中,这里需要将JDK提供的javax.security.auth.callback.Callback转型为WSS4J提供的org.apache.wss4j.common.ext.WSPasswordCallback,在handle方法中实现对客户端密码的验证,最终需要将密码放入到callback对象中。
package com.test.handler;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.wss4j.common.ext.WSPasswordCallback;
public class ClientPasswordCallback implements CallbackHandler {
@Override
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback callback = (WSPasswordCallback) callbacks[0];
callback.setPassword("clientpass");
}
}
在ClientPasswordCallback中,无非是这只客户端用户的密码,其他的什么也不用做了,客户端密码只能通过回调处理器的方式进行提供,而不能再spring配置文件中进行配置。
client clientpass cxf
client HvElE//KB8gGhIv5u8RKI+hoUYc= 2+E62ViJx7kbw13ZlMgGBA== 2016-11-28T02:57:07.932Z cxf
除了这种基于用户名与密码的身份认证方式外,还有一种更加安全的身份认证方式,名为“数字签名”。
@echo off
keytool -genkeypair -alias server -keyalg RSA -dname "cn=server" -keypass serverpass -keystore server_store.jks -storepass storepass
keytool -exportcert -alias server -file server_key.rsa -keystore server_store.jks -storepass storepass
keytool -importcert -alias server -file server_key.rsa -keystore client_store.jks -storepass storepass -noprompt
del server_key.rsa
keytool -genkeypair -alias client -dname "cn=client" -keyalg RSA -keypass clientpass -keystore client_store.jks -storepass storepass
keytool -exportcert -alias client -file client_key.rsa -keystore client_store.jks -storepass storepass
keytool -importcert -alias client -file client_key.rsa -keystore server_store.jks -storepass storepass -noprompt
del client_key.rsa
在以上这些命令中,使用了 JDK 提供的 keytool
命令行工具,关于该命令的使用方法,可点击以下链接:
org.apache.ws.security.crypto.provider=org.apache.wss4j.common.crypto.Merlin
org.apache.ws.security.crypto.merlin.file=server_store.jks
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=storepass
org.apache.ws.security.crypto.provider=org.apache.wss4j.common.crypto.Merlin
org.apache.ws.security.crypto.merlin.file=client_store.jks
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=storepass
此外,客户端同样需要提供签名用户(signatureUser)和密码回调处理器(passwordCallbackRef)。
+CL/+5vsXW07y9PThudROCUYV30= PfqRLe2lIKHOLC/LGGsVdMLFTPx9/88fGDNLgwAWS+/XTsVvPRKF5tAEGo5KQ1bO2DBSUeJzCV776EKXC6S1GGDP70DU43eyOPfnZfYPF8NJZQFCJJe9Ir1lUZ8XJNEK9Puriw2XM/UO+P4/OJVRJql/EFFuhES1cNlsvDxM5yYkfEwKhv8qc5IuwvviJMN7jIbrQOFP8/xDE35wabrLp+xOUNLGRiyWDPAVEb+rYdPbHwJHVo/KwWKkje43IRIFc+KXL833aQHm27UBWuOcHl5tL4aZHydcc8/UvWU7IK9soU+zis3R1z9Ks9jwDlsHkvR6xT+cCGxfsKSqR4m+ZA== CN=client 508496482 cxf
可见,数字签名是一种更为安全的身份认证方式,但无法对SOAP Body中的数据进行加密,究竟怎样才能加密并解密SOAP中的数据呢?
CN=server 979617998 fk/AirRnUfefQwjWViwuCNbKM7KbVVKLwF5xn+V1g4XfHZZ8/i/QrXcfnmGcojub8nvLZNg6ux2/PT+Nay6Sb9+PRuC8vqsGSbWSVRv9P1nNMpN4Ie5CBCwLM9iYCfgMSCx9KfqnRyxFlQBRcHmVKhwicUuszFSR/IrZ1BGAjtJw11EO5cCSmKJcrI2Pl8qB63u2LUE8lN0TjbkoIo9ll/PlamL5sw06rTa1ZDa/07rUZzIfhoU4grRHCY1skkdy3RQwnjG3mgpve7eZ1DTf05y3TW+NDQgDpv871V/nS4x0thYIIX6umgIOFMoV/MGzQ1ccyADNh8P27lI7yjbI4g== INGDwn+fnUGbhuwdNCvujDahddc= NASMeogydnAQE0oAEDf0V1/llihU2kuD/R0ZforidXDX+EJOZkfQ6uc1XIhZGI31yxYjZ5h3WxSZaIJuurxPZiq+DNlDEKUntYKMOKljClJyjjZTCGUor7fuiIgh9W2tbarQewxfWRes0I5kNWREebpyN3qkYMb0MRBwl5r2J8guJYCgr2zVvK6Bo08aSuIpSR3/ylrAgV3UaVIsM00fV9OEXFYpbSJGbrE+VV2uoDoCjN805MT0kyaYjOTPQSZdYNy/pnGUV8uxVVD55lKIdiyabnGC+J+wG2u80JeILb5m6wvtLyHSk2bgQeAqdZ3DTqTz7Bn6Up4xX8C0L+ifrw== CN=client 508496482 BWCrzKudYIxdpOOCE+y3cSnSoJiZu22p4FxgSR2grJ8IVD2hHmMTBQlPT+o1RruK3kg6jM/fGlgabHzpwHBQ+z4uTTsAuXAnkkAeB9UPaxC2iZ0b9y4kBlCD/qQEBb6M+vRD05SvIgv5QhJPpf72Vg==
本文的内容有些多,确实需要稍微总结一下: