在按照网上的例子进行配置用户名令牌的例子,在server端的回调函数中获取的password 却一直是空,搜索了好半天,才找到(这个是MD5加密的):
WSPasswordCallback 的passwordType属性和password 属性都为null,你只能获得用户名(identifier),一般这里的逻辑是使用这个用户名到数据库中查询其密码,然后再设置到password 属性,WSS4J 会自动比较客户端传来的值和你设置的这个值。你可能会问为什么这里CXF 不把客户端提交的密码传入让我们在ServerPasswordCallbackHandler 中比较呢?这是因为客户端提交过来的密码在SOAP 消息中已经被加密为MD5 的字符串,如果我们要在回调方法中作比较,那么第一步要做的就是把服务端准备好的密码加密为MD5 字符串,由于MD5 算法参数不同结果也会有差别,另外,这样的工作CXF 替我们完成不是更简单吗?
根据上面说的,我获取的password 为null,所以这里就不用自己判断密码了,只要验证用户名后,在设置密码就可以自动验证了,代码如下:
01 | public class ServerPasswordCallback implements CallbackHandler { |
02 | |
03 | public void handle(Callback[] callbacks) throws IOException, |
04 | UnsupportedCallbackException { |
05 | WSPasswordCallback pc = (WSPasswordCallback) callbacks[ 0 ]; |
06 | String pw = pc.getPassword(); |
07 | String idf = pc.getIdentifier(); |
08 | System.out.println( "password:" +pw); |
09 | System.out.println( "identifier:" +idf); |
10 | if (idf.endsWith( "admin" )){ |
11 | pc.setPassword( "admin" ); |
12 | } |
13 | } |
14 | |
15 | } |
以下是源代码:
HelloWorld.java
1 | package com.mms.webservice; |
2 | import javax.jws.WebService; |
3 | @WebService |
4 | public interface HelloWorld { |
5 | String sayHi(String text); |
6 | } |
HelloWorldImpl.java
01 | package com.mms.webservice; |
02 | import javax.annotation.Resource; |
03 | import javax.jws.WebService; |
04 | import javax.servlet.http.HttpServletRequest; |
05 | import javax.servlet.http.HttpSession; |
06 | import javax.xml.ws.WebServiceContext; |
07 | import javax.xml.ws.handler.MessageContext; |
08 | import org.apache.cxf.transport.http.AbstractHTTPDestination; |
09 |
10 | @WebService |
11 | public class HelloWorldImpl implements HelloWorld { |
12 | public String sayHi(String text) { |
13 | return "Hello " + text; |
14 | } |
15 | } |
ServerPasswordCallback.java
01 | package com.mms.webservice.test; |
02 | import java.io.IOException; |
03 | import java.util.HashMap; |
04 | import java.util.Map; |
05 | import javax.security.auth.callback.Callback; |
06 | import javax.security.auth.callback.CallbackHandler; |
07 | import javax.security.auth.callback.UnsupportedCallbackException; |
08 | import org.apache.ws.security.WSPasswordCallback; |
09 | import org.apache.ws.security.WSSecurityException; |
10 |
11 | public class ServerPasswordCallback implements CallbackHandler { |
12 |
13 | private Map<String, String> passwords = new HashMap<String, String>(); |
14 |
15 | public ServerPasswordCallback() { |
16 | passwords.put( "admin" , "admin" ); |
17 | passwords.put( "test" , "test" ); |
18 | } |
19 |
20 | public void handle(Callback[] callbacks) throws IOException, |
21 | UnsupportedCallbackException { |
22 | System.out.println( "server:callbacks.length-" +callbacks.length); |
23 | for ( int i = 0 ; i < callbacks.length; i++) { |
24 | WSPasswordCallback pc = (WSPasswordCallback) callbacks[i]; |
25 | if (!passwords.containsKey(pc.getIdentifier())) |
26 | try { |
27 | throw new WSSecurityException( "user not match" ); |
28 | } catch (WSSecurityException e) { |
29 | e.printStackTrace(); |
30 | } |
31 | String pass = passwords.get(pc.getIdentifier()); |
32 | pc.setPassword(pass); |
33 | } |
34 | } |
35 |
36 | } |
ClientPasswordCallback .java
01 | package com.mms.client; |
02 | import java.io.IOException; |
03 | import java.util.HashMap; |
04 | import java.util.Map; |
05 | import javax.security.auth.callback.Callback; |
06 | import javax.security.auth.callback.CallbackHandler; |
07 | import javax.security.auth.callback.UnsupportedCallbackException; |
08 | import org.apache.ws.security.WSPasswordCallback; |
09 | import org.apache.ws.security.WSSecurityException; |
10 |
11 | public class ClientPasswordCallback implements CallbackHandler { |
12 |
13 | private Map<String, String> passwords = new HashMap<String, String>(); |
14 |
15 | public ClientPasswordCallback() { |
16 | passwords.put( "admin" , "admin" ); |
17 | passwords.put( "test" , "test" ); |
18 | } |
19 |
20 | public void handle(Callback[] callbacks) throws IOException, |
21 | UnsupportedCallbackException { |
22 | System.out.println( "client:callbacks.length-" +callbacks.length); |
23 | for ( int i = 0 ; i < callbacks.length; i++) { |
24 | WSPasswordCallback pc = (WSPasswordCallback) callbacks[i]; |
25 | int usage = pc.getUsage(); |
26 | if (!passwords.containsKey(pc.getIdentifier())) |
27 | try { |
28 | throw new WSSecurityException( "user not exists " ); |
29 | } catch (WSSecurityException e) { |
30 | e.printStackTrace(); |
31 | } |
32 | String pass = passwords.get(pc.getIdentifier()); |
33 | if (usage == WSPasswordCallback.USERNAME_TOKEN && pass != null ) { |
34 | System.out.println( "client:pass" +pass); |
35 | pc.setPassword(pass); |
36 | return ; |
37 | } |
38 | } |
39 | } |
40 |
41 | } |
web.xml
01 | <? xml version = "1.0" encoding = "UTF-8" ?> |
02 | < web-app version = "2.5" |
03 | xmlns = "http://java.sun.com/xml/ns/javaee" |
04 | xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" |
05 | xsi:schemaLocation="http://java.sun.com/xml/ns/javaee |
06 | http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> |
07 | < welcome-file-list > |
08 | < welcome-file >index.jsp</ welcome-file > |
09 | </ welcome-file-list > |
10 | < context-param > |
11 | < param-name >contextConfigLocation</ param-name > |
12 | < param-value > |
13 | classpath:server.xml classpath:client.xml |
14 | </ param-value > |
15 | </ context-param > |
16 |
17 | < listener > |
18 | < listener-class > |
19 | org.springframework.web.context.ContextLoaderListener |
20 | </ listener-class > |
21 | </ listener > |
22 |
23 | < servlet > |
24 | < servlet-name >CXFServlet</ servlet-name > |
25 | < servlet-class > |
26 | org.apache.cxf.transport.servlet.CXFServlet |
27 | </ servlet-class > |
28 | </ servlet > |
29 |
30 | < servlet-mapping > |
31 | < servlet-name >CXFServlet</ servlet-name > |
32 | < url-pattern >/*</ url-pattern > |
33 | </ servlet-mapping > |
34 | </ web-app > |
客户端spring配置文件:client.xml
01 | <? xml version = "1.0" encoding = "UTF-8" ?> |
02 | < beans xmlns = "http://www.springframework.org/schema/beans" |
03 | xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws = "http://cxf.apache.org/jaxws" |
04 | xsi:schemaLocation=" |
05 | http://www.springframework.org/schema/beans |
06 | http://www.springframework.org/schema/beans/spring-beans.xsd |
07 | http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> |
08 |
09 | <!-- 定义客户端的拦截器对象 --> |
10 | < bean id = "logIn" class = "org.apache.cxf.interceptor.LoggingInInterceptor" /> |
11 | < bean id = "logOut" class = "org.apache.cxf.interceptor.LoggingOutInterceptor" /> |
12 | < bean id = "saajOut" class = "org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" /> |
13 | <!-- <bean id="soapheaderOut" class="com.mms.client.writeSOAPHeaderInterceptor" /> --> |
14 | < bean id = "wss4jOut" class = "org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor" > |
15 | < constructor-arg > |
16 | < map > |
17 | < entry key = "action" value = "UsernameToken" /> |
18 | < entry key = "passwordType" value = "PasswordText" /> |
19 | < entry key = "user" value = "admin" /> |
20 | < entry key = "passwordCallbackClass" value = "com.mms.client.ClientPasswordCallback" /> |
21 | </ map > |
22 | </ constructor-arg > |
23 | </ bean > |
24 | <!-- 客户端的配置 --> |
25 | < jaxws:client id = "client" serviceClass = "com.mms.webservice.HelloWorld" address = "http://127.0.0.1:8080/CXFSecurity/HelloWorld" > |
26 | < jaxws:inInterceptors > |
27 | < ref bean = "logIn" /> |
28 | </ jaxws:inInterceptors > |
29 | < jaxws:outInterceptors > |
30 | < ref bean = "logOut" /> |
31 | < ref bean = "saajOut" /> |
32 | <!--<ref bean="soapheaderOut" /> --> |
33 | < ref bean = "wss4jOut" /> |
34 | </ jaxws:outInterceptors > |
35 | </ jaxws:client > |
36 | </ beans > |
服务器spring配置文件:server.xml
01 | < beans xmlns = "http://www.springframework.org/schema/beans" |
02 | xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws = "http://cxf.apache.org/jaxws" |
03 | xsi:schemaLocation=" |
04 | http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd |
05 | http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> |
06 | <!-- jar包中自带的cxf文件夹下的*.xml文件 --> |
07 | < import resource = "classpath:META-INF/cxf/cxf.xml" /> |
08 | < import resource = "classpath:META-INF/cxf/cxf-extension-soap.xml" /> |
09 | < import resource = "classpath:META-INF/cxf/cxf-servlet.xml" /> |
10 | <!-- 定义服务端的拦截器对象 --> |
11 | < bean id = "logIn" class = "org.apache.cxf.interceptor.LoggingInInterceptor" /> |
12 | < bean id = "logOut" class = "org.apache.cxf.interceptor.LoggingOutInterceptor" /> |
13 | < bean id = "saajIn" class = "org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" /> |
14 | <!-- <bean id="soapheaderIn" class="com.mms.webservice.test.readSOAPHeaderInterceptor" /> --> |
15 | < bean id = "wss4jIn" class = "org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor" > |
16 | < constructor-arg > |
17 | < map > |
18 | < entry key = "action" value = "UsernameToken" /> |
19 | < entry key = "passwordType" value = "PasswordText" /> |
20 | < entry key = "passwordCallbackClass" value = "com.mms.webservice.test.ServerPasswordCallback" /> |
21 | </ map > |
22 | </ constructor-arg > |
23 | </ bean > |
24 | < jaxws:endpoint id = "helloWorld" implementor = "com.mms.webservice.HelloWorldImpl" |
25 | address = "/HelloWorld" > |
26 | < jaxws:inInterceptors > |
27 | < ref bean = "logIn" /> |
28 | < ref bean = "saajIn" /> |
29 | <!--<ref bean="soapheaderIn" /> --> |
30 | < ref bean = "wss4jIn" /> |
31 | </ jaxws:inInterceptors > |
32 | < jaxws:outInterceptors > |
33 | < ref bean = "logOut" /> |
34 | </ jaxws:outInterceptors > |
35 | </ jaxws:endpoint > |
36 |
37 | </ beans > |
测试Client.java
01 | package com.mms.client; |
02 | import org.springframework.context.ApplicationContext; |
03 | import org.springframework.context.support.ClassPathXmlApplicationContext; |
04 | import com.mms.webservice.HelloWorld; |
05 |
06 | public final class Client { |
07 |
08 | private Client() { |
09 | } |
10 |
11 | public static void main(String args[]) throws Exception { |
12 | ApplicationContext context = new ClassPathXmlApplicationContext( |
13 | new String[] { "client.xml" }); |
14 | HelloWorld client = (HelloWorld) context.getBean( "client" ); |
15 | String response = client.sayHi( "hello test!" ); |
16 | System.out.println( "Response: " + response); |
17 | } |
18 | } |