zoukankan      html  css  js  c++  java
  • CXF 入门:创建一个基于WS-Security标准的安全验证(CXF回调函数使用)

    注意:以下客户端调用代码中获取服务端ws实例,都是通过CXF 入门: 远程接口调用方式实现

    以下是服务端配置

    ========================================================

    一,web.xml配置,具体不在详述

    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <!DOCTYPE web-app  
    3.     PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"  
    4.     "http://java.sun.com/dtd/web-app_2_3.dtd">  
    5. <web-app>  
    6.     <context-param>  
    7.         <param-name>contextConfigLocation</param-name>  
    8.         <!--ws-context.xml(必须)是cxf配置文件, wssec.xml可选,作用可以打印出加密信息类容 -->  
    9.         <param-value>WEB-INF/ws-context.xml,WEB-INF/wssec.xml</param-value>  
    10.     </context-param>  
    11.   
    12.     <listener>  
    13.         <listener-class>  
    14.             org.springframework.web.context.ContextLoaderListener  
    15.         </listener-class>  
    16.     </listener>  
    17.   
    18.     <servlet>  
    19.         <servlet-name>CXFServlet</servlet-name>  
    20.         <display-name>CXF Servlet</display-name>  
    21.         <servlet-class>  
    22.             org.apache.cxf.transport.servlet.CXFServlet  
    23.         </servlet-class>  
    24.         <load-on-startup>0</load-on-startup>  
    25.     </servlet>  
    26.   
    27.     <servlet-mapping>  
    28.         <servlet-name>CXFServlet</servlet-name>  
    29.         <url-pattern>/services/*</url-pattern>  
    30.     </servlet-mapping>  
    31. </web-app>  

     二,ws具体代码
    简单的接口

    1. import javax.jws.WebService;  
    2.   
    3. @WebService()  
    4. public interface WebServiceSample {  
    5.     String say(String name);  
    6.   
    7. }  

    接口具体实现类

    1. public class WebServiceSampleImpl implements WebServiceSample {  
    2.   
    3.     public String say(String name) {  
    4.         return "你好," + name;  
    5.     }  
    6. }  

     

    三,ws回调函数,必须实现javax.security.auth.callback.CallbackHandler

    从cxf2.4.x后校验又cxf内部实现校验,所以不必自己校验password是否相同,但客户端必须设置,详情请参考:http://cxf.apache.org/docs/24-migration-guide.html的Runtime  Changes片段

    回调函数WsAuthHandler代码,校验客户端请求是否合法 ,合法就放行,否则拒绝执行任何操作

    1. import java.io.IOException;  
    2. import javax.security.auth.callback.Callback;  
    3. import javax.security.auth.callback.CallbackHandler;  
    4. import javax.security.auth.callback.UnsupportedCallbackException;  
    5. import org.apache.cxf.interceptor.Fault;  
    6. import org.apache.ws.security.WSPasswordCallback;  
    7. import org.apache.xmlbeans.impl.soap.SOAPException;  
    8.   
    9. public class WsAuthHandler implements CallbackHandler {  
    10.   
    11.     public void handle(Callback[] callbacks) throws IOException,  
    12.             UnsupportedCallbackException {  
    13.         for (int i = 0; i < callbacks.length; i++) {  
    14.             WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];  
    15.             String identifier = pc.getIdentifier();  
    16.             int usage = pc.getUsage();  
    17.             if (usage == WSPasswordCallback.USERNAME_TOKEN) {// 密钥方式USERNAME_TOKEN  
    18.                 // username token pwd...  
    19.                 // ▲这里的值必须和客户端设的值相同,从cxf2.4.x后校验方式改为cxf内部实现校验,不必自己比较password是否相同  
    20.                 // 请参考:http://cxf.apache.org/docs/24-migration-guide.html的Runtime  
    21.                 // Changes片段  
    22.                 pc.setPassword("testPassword");// ▲【这里非常重要】▲  
    23.                 // ▲PS 如果和客户端不同将抛出org.apache.ws.security.WSSecurityException:  
    24.                 // The  
    25.                 // security token could not be authenticated or  
    26.                 // authorized异常,服务端会认为客户端为非法调用  
    27.             } else if (usage == WSPasswordCallback.SIGNATURE) {// 密钥方式SIGNATURE  
    28.                 // set the password for client's keystore.keyPassword  
    29.                 // ▲这里的值必须和客户端设的值相同,从cxf2.4.x后校验方式改为cxf内部实现校验,不必自己比较password是否相同;  
    30.                 // 请参考:http://cxf.apache.org/docs/24-migration-guide.html的Runtime  
    31.                 // Changes片段  
    32.                 pc.setPassword("testPassword");// //▲【这里非常重要】▲  
    33.                 // ▲PS:如果和客户端不同将抛出org.apache.ws.security.WSSecurityException:The  
    34.                 // security token could not be authenticated or  
    35.                 // authorized异常,服务端会认为客户端为非法调用  
    36.             }  
    37.             //不用做其他操作  
    38.         }  
    39.     }  
    40. }  

     

    四,CXF配置ws-context.xml:

    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"  
    3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"  
    4.     xsi:schemaLocation="  
    5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
    6. http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">  
    7.   
    8.     <import resource="classpath:META-INF/cxf/cxf.xml" />  
    9.     <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />  
    10.     <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />  
    11.     <!-- 以上未基本配置,必须,位置在cxf jar中 -->  
    12.     <jaxws:endpoint id="webServiceSample" address="/WebServiceSample"  
    13.         implementor="com.service.impl.WebServiceSampleImpl">  
    14.         <!--inInterceptors表示被外部调用时,调用此拦截器 -->  
    15.         <jaxws:inInterceptors>  
    16.             <bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" />  
    17.             <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">  
    18.                 <constructor-arg>  
    19.                     <map>  
    20.                         <!-- 设置加密类型 -->  
    21.                         <entry key="action" value="UsernameToken" />  
    22.                         <!-- 设置密码类型为明文 -->  
    23.                         <entry key="passwordType" value="PasswordText" />  
    24.                         <!--<entry key="action" value="UsernameToken Timestamp" /> 设置密码类型为加密<entry   
    25.                             key="passwordType" value="PasswordDigest" /> -->  
    26.                         <entry key="passwordCallbackClass" value="com.service.handler.WsAuthHandler" />  
    27.                     </map>  
    28.                 </constructor-arg>  
    29.             </bean>  
    30.         </jaxws:inInterceptors>  
    31.     </jaxws:endpoint>  
    32. </beans>  

    CXF配置wssec.xml(可选),用于配置输出校验的具体信息

    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"  
    3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cxf="http://cxf.apache.org/core"  
    4.     xmlns:wsa="http://cxf.apache.org/ws/addressing" xmlns:http="http://cxf.apache.org/transports/http/configuration"  
    5.     xmlns:wsrm-policy="http://schemas.xmlsoap.org/ws/2005/02/rm/policy"  
    6.     xmlns:wsrm-mgr="http://cxf.apache.org/ws/rm/manager"  
    7.     xsi:schemaLocation="  
    8.        http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd  
    9.        http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd  
    10.        http://schemas.xmlsoap.org/ws/2005/02/rm/policy http://schemas.xmlsoap.org/ws/2005/02/rm/wsrm-policy.xsd  
    11.        http://cxf.apache.org/ws/rm/manager http://cxf.apache.org/schemas/configuration/wsrm-manager.xsd  
    12.        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  
    13.     <cxf:bus>  
    14.         <cxf:features>  
    15.             <cxf:logging />  
    16.             <wsa:addressing />  
    17.         </cxf:features>  
    18.     </cxf:bus>  
    19. </beans>  

    服务端代码及配置到此结束!!!

    =========================================================

    =========================================================

    以下是客户端配置,主要是回调函数,在客户端调用服务端前被调用,负责安全信息的设置

    ----------------------------------------------------------------------------------------

    一,先实现回调函数WsClinetAuthHandler,同样必须实现javax.security.auth.callback.CallbackHandler

    1. import java.io.IOException;  
    2. import javax.security.auth.callback.Callback;  
    3. import javax.security.auth.callback.CallbackHandler;  
    4. import javax.security.auth.callback.UnsupportedCallbackException;  
    5. import org.apache.ws.security.WSPasswordCallback;  
    6.   
    7. public class WsClinetAuthHandler implements CallbackHandler {  
    8.   
    9.     public void handle(Callback[] callbacks) throws IOException,  
    10.             UnsupportedCallbackException {  
    11.         for (int i = 0; i < callbacks.length; i++) {  
    12.             WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];  
    13.             System.out.println("identifier: " + pc.getIdentifier());  
    14.             // 这里必须设置密码,否则会抛出:java.lang.IllegalArgumentException: pwd == null  
    15.             // but a password is needed  
    16.             pc.setPassword("testPassword");// ▲【这里必须设置密码】▲  
    17.         }  
    18.     }  
    19. }  
     

    二,客户端调用代码:

    1. import java.util.ArrayList;  
    2. import java.util.HashMap;  
    3. import java.util.Map;  
    4.   
    5. import org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor;  
    6. import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;  
    7. import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;  
    8. import org.apache.ws.security.WSConstants;  
    9. import org.apache.ws.security.handler.WSHandlerConstants;  
    10.   
    11. import test.saa.client.WebServiceSample;  
    12. import test.saa.handler.WsClinetAuthHandler;  
    13.   
    14. public class TestClient {  
    15.   
    16.     public static void main(String[] args) {  
    17.         // 以下和服务端配置类似,不对,应该说服务端和这里的安全验证配置一致  
    18.         Map<String, Object> outProps = new HashMap<String, Object>();  
    19.         outProps.put(WSHandlerConstants.ACTION,  
    20.                 WSHandlerConstants.USERNAME_TOKEN);  
    21.         outProps.put(WSHandlerConstants.USER, "admin");  
    22.         outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);  
    23.         // 指定在调用远程ws之前触发的回调函数WsClinetAuthHandler,其实类似于一个拦截器  
    24.         outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,  
    25.                 WsClinetAuthHandler.class.getName());  
    26.         ArrayList list = new ArrayList();  
    27.         // 添加cxf安全验证拦截器,必须  
    28.         list.add(new SAAJOutInterceptor());  
    29.         list.add(new WSS4JOutInterceptor(outProps));  
    30.   
    31.         JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();  
    32.         // WebServiceSample服务端接口实现类,这里并不是直接把服务端的类copy过来,具体请参考http://learning.iteye.com/blog/1333223  
    33.         factory.setServiceClass(WebServiceSample.class);  
    34.         // 设置ws访问地址  
    35.         factory.setAddress("http://localhost:8080/cxf-wssec/services/WebServiceSample");  
    36.         //注入拦截器,用于加密安全验证信息  
    37.         factory.getOutInterceptors().addAll(list);  
    38.         WebServiceSample service = (WebServiceSample) factory.create();  
    39.         String response = service.say("2012");  
    40.         System.out.println(response);  
    41.     }  
    42. }  

     客户端到此结束!!!!

    ========================================================================

    #######################################################################

    PS:客户端的另一种调用方式,主要通过配置文件,不过需要spring bean的配置文件(第一种就不用牵扯到spring的配置,比较通用吧!)

    一,回调函数WsClinetAuthHandler不变,和上面一样
    二,client-beans.xml安全验证配置文件,具体信息看注释,如下:

    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <beans xmlns="http://www.springframework.org/schema/beans"  
    3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"  
    4.     xsi:schemaLocation="  
    5. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd  
    6. http://cxf.apache.org/jaxws http://cxf.apache.org/schema/jaxws.xsd">  
    7. <!--这里无非是通过配置来替代JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean()创建代理并实例化一个ws-->  
    8.     <bean id="client" class="test.saa.client.WebServiceSample"  
    9.         factory-bean="clientFactory" factory-method="create" />  
    10.     <!-- 通过代理创建ws实例 -->  
    11.     <bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">  
    12.         <property name="serviceClass" value="test.saa.client.WebServiceSample" />  
    13.         <!-- ws地址,也可以是完整的wsdl地址 -->  
    14.         <property name="address"  
    15.             value="http://localhost:8080/cxf-wssec/services/WebServiceSample" />  
    16.         <!--outInterceptors表示调用外部指定ws时,调用此拦截器 -->  
    17.         <property name="outInterceptors">  
    18.             <list>  
    19.                 <bean class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" />  
    20.                 <ref bean="wss4jOutConfiguration" />  
    21.             </list>  
    22.         </property>  
    23.     </bean>  
    24.   
    25.     <bean id="wss4jOutConfiguration" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">  
    26.         <property name="properties">  
    27.             <map>  
    28.                 <!-- 设置加密类型 ,服务端需要和这里的设置保持一致-->  
    29.                 <entry key="action" value="UsernameToken" />  
    30.                 <entry key="user" value="admin" />  
    31.                 <!-- 设置密码为明文 ,服务端需要和这里的设置保持一致-->  
    32.                 <entry key="passwordType" value="PasswordText" />  
    33.                 <!-- <entry key="action" value="UsernameToken Timestamp" /> <entry key="user"   
    34.                     value="adminTest" /> 设置密码类型为加密方式,服务端需要和这里的设置保持一致<entry key="passwordType" value="PasswordDigest"   
    35.                     /> -->  
    36.                 <entry key="passwordCallbackRef">  
    37.                     <ref bean="passwordCallback" />  
    38.                 </entry>  
    39.             </map>  
    40.         </property>  
    41.     </bean>  
    42.     <bean id="passwordCallback" class="test.saa.handler.WsClinetAuthHandler" />  
    43. </beans>  

     
    三,具体调用服务端代码:

      1. import org.springframework.context.ApplicationContext;  
      2. import org.springframework.context.support.ClassPathXmlApplicationContext;  
      3.   
      4. import test.saa.client.WebServiceSample;  
      5.   
      6. public final class Client {  
      7.   
      8.     public static void main(String args[]) throws Exception {  
      9.     //加载配置  
      10.         ApplicationContext context = new ClassPathXmlApplicationContext(  
      11.                 new String[] { "test/saa/client-beans.xml" });  
      12.         //获取ws实例  
      13.         WebServiceSample client = (WebServiceSample) context.getBean("client");  
      14.         String response = client.say("2012");  
      15.         System.out.println("Response: " + response);  
      16.     }  
      17. }  
  • 相关阅读:
    【Anagrams】 cpp
    【Count and Say】cpp
    【Roman To Integer】cpp
    【Integer To Roman】cpp
    【Valid Number】cpp
    重构之 实体与引用 逻辑实体 逻辑存在的形式 可引用逻辑实体 不可引用逻辑实体 散弹式修改
    Maven项目聚合 jar包锁定 依赖传递 私服
    Oracle学习2 视图 索引 sql编程 游标 存储过程 存储函数 触发器
    mysql案例~tcpdump的使用
    tidb架构~本地化安装
  • 原文地址:https://www.cnblogs.com/wdpnodecodes/p/7407284.html
Copyright © 2011-2022 走看看