?
? ?基于 spring + apache cxf
?
1.服务器端 cxf配置:
<?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"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xsi:schemaLocation="
?http://www.springframework.org/schema/beans?
?http://www.springframework.org/schema/beans/spring-beans.xsd?
?http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
?http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">
?
? ? <import resource="classpath:META-INF/cxf/cxf.xml" /> ?
? ? <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> ?
? ??
<jaxws:endpoint id="greetingService"
implementor="com.test.service.impl.GreetingServiceImpl"?
address="/greetingService" >
<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="cxfUser" /> ??
? ? ? ? ? ? ? ? ? ? ? ? <entry key="passwordCallbackRef"> ??
? ? ? ? ? ? ? ? ? ? ? ? ? ? <ref bean="serverPasswordCallback" /> ??
? ? ? ? ? ? ? ? ? ? ? ? </entry> ??
? ? ? ? ? ? ? ? ? ? </map> ??
? ? ? ? ? ? ? ? </constructor-arg> ??
? ? ? ? ? ? </bean> ??
? ? ? ? </jaxws:inInterceptors> ??
? ? </jaxws:endpoint>
<bean id="serverPasswordCallback" ?
? ? ? ?class="com.common.cxf.ServerPasswordCallback" /> ??
</beans>?
说明:
? ?action:UsernameToken指使用用户令牌?
??? passwordType:PasswordText指密码加密策略,这里直接文本?
??? user:cxfServer指别名?
??? passwordCallBackRef:serverPasswordCallback指消息验证?
?
2.服务器端?CallbackHandler 拦截处理
package com.core.common.cxf;
?
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 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 (idf.equals("admin")) { ??
? ? ? ? pc.setPassword("josen");
? ? ? ? } else { ??
? ? ? ? ? ? throw new SecurityException("验证失败"); ??
? ? ? ? } ??
? ? } ??
??
?
} ?
说明:
?
??WSPasswordCallback 的passwordType属性和password 属性都为null,你只能获得用户名(identifier),一般这里的逻辑是使用这个用户名到数据库中查询其密码,然后再设置到password 属性,WSS4J 会自动比较客户端传来的值和你设置的这个值。你可能会问为什么这里CXF 不把客户端提交的密码传入让我们在ServerPasswordCallbackHandler 中比较呢?这是因为客户端提交过来的密码在SOAP 消息中已经被加密为MD5 的字符串,如果我们要在回调方法中作比较,那么第一步要做的就是把服务端准备好的密码加密为MD5 字符串,由于MD5 算法参数不同结果也会有差别,另外,这样的工作CXF 替我们完成不是更简单吗?
?
根据上面说的,我获取的password 为null,所以这里就不用自己判断密码了,只要验证用户名后,在设置密码就可以自动验证了
3.客户端配置文件:
<?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"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xsi:schemaLocation="
?http://www.springframework.org/schema/beans?
?http://www.springframework.org/schema/beans/spring-beans.xsd?
?http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
?http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">
?
? <jaxws:client id="greetingService" serviceClass="com.test.service.GreetingService"?
? address="http://localhost:8080/test/greetingService">
?
? ? ? ? ? <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="cxfUser" /> ??
? ? ? ? ? ? ? ? ? ? ? ? <entry key="passwordCallbackRef"> ??
? ? ? ? ? ? ? ? ? ? ? ? ? ? <ref bean="clientPasswordCallback" /> ??
? ? ? ? ? ? ? ? ? ? ? ? </entry> ??
? ? ? ? ? ? ? ? ? ? </map> ??
? ? ? ? ? ? ? ? </constructor-arg> ??
? ? ? ? ? ? </bean> ??
? ? ? ? </jaxws:outInterceptors>?
? ? </jaxws:client> ??
? ? <bean id="clientPasswordCallback" ?
? ? ? ? class="com.common.cxf.ClientPasswordCallback" /> ??
?
</beans>?
4.客户端CallbackHandler
package com.common.cxf;
?
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 { ??
??
? ? 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"); ??
? ? ? ? } ??
? ? } ??
??
?
} ?
? ? 说明:
? 只要两边的?Identifier,Password 相同就ok了