这一节我们来探讨一下WebService安全问题,如果所有系统都运行在一个封闭的局域网内,那么可以不考虑网络攻击,拒绝服务,消息篡改,窃取等问题。但通常情况都接入互联网,那么我就得考虑信息安全问题,像前面那样直接将消息裸传,肯定不行。那么,我们就得给消息加密。CXF可以结合WSS4J来对消息安全进行管理,可以使用令牌,X.509认证对消息头或内容进行加密。这节我只对令牌加密做一个简单的描述,我们还以Demo的形式来讲解一下。
这个Demo是在CXF+Spring+Hibernate的基础修改而成。在这里我只针对修改的东西进行讲解。
<?xml version=
"1.0" encoding=
"UTF-8"?>
<beans xmlns=
"http://www.springframework.org/schema/beans"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws=
"http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http:
http:
http:
http:
<
import resource=
"classpath:META-INF/cxf/cxf.xml" />
<
import resource=
"classpath:META-INF/cxf/cxf-extension-soap.xml" />
<
import resource=
"classpath:META-INF/cxf/cxf-servlet.xml" />
<jaxws:endpoint id=
"service"
implementor=
"com.itdcl.service.ServiceImpl" address=
"/Service">
<jaxws:inInterceptors>
<bean
class=
"org.apache.cxf.interceptor.LoggingInInterceptor" />
<bean
class=
"org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" />
<bean
class=
"org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
<constructor-arg>
<map>
<entry key=
"action" value=
"UsernameToken" />
<entry key=
"passwordType"
value=
"PasswordText" />
<entry key=
"user" value=
"cxfServer" />
<entry key=
"passwordCallbackRef">
<ref bean=
"serverPasswordCallback" />
</entry>
</map>
</constructor-arg>
</bean>
</jaxws:inInterceptors>
</jaxws:endpoint>
<bean id=
"serverPasswordCallback"
class=
"com.itdcl.ws.ServerPasswordCallback" />
</beans>
action:UsernameToken指使用用户令牌
passwordType:PasswordText指密码加密策略,这里直接文本
user:cxfServer指别名
passwordCallBackRef:serverPasswordCallback指消息验证
消息验证类:
package com.itdcl.ws;
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.ws.security.WSPasswordCallback;
public class ServerPasswordCallback
implements CallbackHandler {
public void handle(Callback[] callbacks)
throws IOException,
UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[
0];
String pw = pc.getPassword();
String idf = pc.getIdentifier();
System.out.println(
"password:"+pw);
System.out.println(
"identifier:"+idf);
if (pw.equals(
"josen") && idf.equals(
"admin")) {
}
else {
throw new SecurityException(
"验证失败");
}
}
}
消息验证类通过实现CallbackHandler接口,实现handle方法来进行用户认证。
那么,客户端又怎样来验证消息是否确呢。
<?xml version=
"1.0" encoding=
"UTF-8"?>
<beans xmlns=
"http://www.springframework.org/schema/beans"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws=
"http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http:
http:
http:
http:
<jaxws:client id=
"service"
address=
"http://localhost:9999/cxf/Service"
serviceClass=
"com.itdcl.service.IService">
<jaxws:outInterceptors>
<bean
class=
"org.apache.cxf.interceptor.LoggingOutInterceptor" />
<bean
class=
"org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" />
<bean
class=
"org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
<constructor-arg>
<map>
<entry key=
"action" value=
"UsernameToken" />
<entry key=
"passwordType"
value=
"PasswordText" />
<entry key=
"user" value=
"cxfClient" />
<entry key=
"passwordCallbackRef">
<ref bean=
"clientPasswordCallback" />
</entry>
</map>
</constructor-arg>
</bean>
</jaxws:outInterceptors>
</jaxws:client>
<bean id=
"clientPasswordCallback"
class=
"com.itdcl.ws.ClientPasswordCallback" />
</beans>
客户端在发送SOAP时对消息对认证,策略跟服务端一样。但是认证类有所区别:
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.ws.security.WSPasswordCallback;
public class ClientPasswordCallback
implements CallbackHandler {
public void handle(Callback[] callbacks)
throws IOException,
UnsupportedCallbackException {
for(
int i=
0;i<callbacks.length;i++)
{
WSPasswordCallback pc = (WSPasswordCallback)callbacks[i];
pc.setPassword(
"josen");
pc.setIdentifier(
"admin");
}
}
}