<!-- 服務端代碼: -->
<jaxws:endpoint id="userWebService" implementor="#userServiceImpl"
address="/userservice">
<jaxws:inInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingInInterceptor"></bean>
<bean class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" />
<bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor" >
<constructor-arg>
<map>
<entry key="action" value="UsernameToken Timestamp" />
<!-- MD5加密明文密碼 -->
<entry key="passwordType" value="PasswordDigest" />
<entry key="user" value="admin" />
<entry key="passwordCallbackRef" >
<ref bean="serverPasswordCallback" />
</entry>
</map>
</constructor-arg>
</bean>
</jaxws:inInterceptors>
<jaxws:outInterceptors>
<bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"></bean>
</jaxws:outInterceptors>
</jaxws:endpoint>
<bean id="serverPasswordCallback" class="com.cxf.webservice.callback.ServerPasswordCallback"></bean>
com.cxf.webservice.callback.ServerPasswordCallback:
package com.cxf.webservice.callback;
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.log4j.Logger;
import org.apache.ws.security.WSPasswordCallback;
public class ServerPasswordCallback implements CallbackHandler {
Logger log = Logger.getLogger(ServerPasswordCallback.class);
Map<String, String> user = new HashMap<String, String>();
{
user.put("admin", "1234");
user.put("su", "1234");
}
@Override
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
log.debug("handler passwordcallback method....");
WSPasswordCallback wpc = (WSPasswordCallback) callbacks[0];
if (!user.containsKey(wpc.getIdentifier())) {
throw new SecurityException("No Permission!");
}
/*
* 此處特别注意::
* WSPasswordCallback 的passwordType屬性和password 屬性都為null,
* 你隻能獲得使用者名(identifier),
* 一般這裡的邏輯是使用這個使用者名到資料庫中查詢其密碼,
* 然後再設定到password 屬性,WSS4J 會自動比較用戶端傳來的值和你設定的這個值。
* 你可能會問為什麼這裡CXF 不把用戶端送出的密碼傳入讓我們在ServerPasswordCallbackHandler 中比較呢?
* 這是因為用戶端送出過來的密碼在SOAP 消息中已經被加密為MD5 的字元串,
* 如果我們要在回調方法中作比較,那麼第一步要做的就是把服務端準備好的密碼加密為MD5 字元串,
* 由于MD5 算法參數不同結果也會有差别,另外,這樣的工作CXF 替我們完成不是更簡單嗎?
*/
wpc.setPassword(user.get(wpc.getIdentifier()));//如果包含使用者名,就設定該使用者名正确密碼,由CXF驗證密碼
String username = wpc.getIdentifier();
String password = wpc.getPassword();
log.debug("username: "+username + " password: "+password);
log.info("User : "+wpc.getIdentifier()+ " login!!!!!");
}
}
<!--用戶端配置-->
<bean id="userService" class="webservice.cxf.client.UserService" factory-bean="clientFactory" factory-method="create" />
<bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="address" value="http://127.0.0.1:8080/HSQLDB/webservice/userservice"></property>
<property name="serviceClass" value="webservice.cxf.client.UserService"></property>
<property name="outInterceptors">
<list>
<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 Timestamp" />
<!-- MD5加密明文密碼 -->
<entry key="passwordType" value="PasswordDigest" />
<entry key="user" value="admin" />
<entry key="passwordCallbackRef">
<ref bean="clientPasswordCallback" />
</entry>
</map>
</constructor-arg>
</bean>
</list>
</property>
</bean>
<bean id="clientPasswordCallback" class="webservice.cxf.clientPasswordCalback.ClientPasswordCallback"></bean>
webservice.cxf.clientPasswordCalback.ClientPasswordCallback:
package webservice.cxf.clientPasswordCalback;
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 {
@Override
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
for (Callback callback : callbacks) {
//設定使用者密碼,供服務端驗證
WSPasswordCallback wsc = (WSPasswordCallback)callback;
wsc.setIdentifier("su");
wsc.setPassword("1234");
}
}
}
Tset:
ApplicationContext app ;
@Before
public void initAPP(){
app = new ClassPathXmlApplicationContext("cxf-client.xml");
}
@Test
public void testSucruty(){
UserService us = (UserService) app.getBean("userService");
System.out.println(us.getAllUser().size());
}