zoukankan      html  css  js  c++  java
  • 带有WS-Security验证的webservice

    示例用的是spring+CXF来配置webservice

    首先是web.xml配置,将spring,CXF的配置文件加载进去,由于我客户端跟服务端在同一个工程里面,所以配置文件在一块。

        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                /WEB-INF/classes/spring-cxf.xml,<!--服务端用到的配置-->
                /WEB-INF/classes/spring-cxf-client.xml<!--客户端用到的配置文件-->
            </param-value>
        </context-param>    
        <servlet>
            <servlet-name>cxf-jeeek</servlet-name>
            <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>cxf-jeeek</servlet-name>
            <url-pattern>/services/*</url-pattern>
        </servlet-mapping>

    一、服务端

      <1>CXF的配置

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:jaxws="http://cxf.apache.org/jaxws"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://cxf.apache.org/jaxws
            http://cxf.apache.org/schemas/jaxws.xsd">
        <import resource="classpath:/META-INF/cxf/cxf.xml" />
        <import resource="classpath:/META-INF/cxf/cxf-servlet.xml" />
        <import resource="classpath:/META-INF/cxf/cxf-extension-soap.xml" />
        <!--配置拦截器,用来验证Token信息-->
        <bean id="exampleServiceInterceptor" class="com.ekservice.interceptor.ExampleServiceInterceptor">
        </bean>
        
        <bean id="exampleServiceImpl" class="com.ekservice.impl.ExampleServiceImpl" />
        <jaxws:endpoint implementor="#exampleServiceImpl" address="/ExampleService">
            <!--  -->
            <jaxws:inInterceptors>
                <bean class="org.apache.cxf.interceptor.LoggingInInterceptor" />
                 <!-- 这个地方不知道为什么,官方文档说CXF2.0.x需要加这个过滤器,但是我用的是CXF2.7.7不加SAAJInInterceptor过滤器报错 -->
                <bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" />
                <bean id="WSS4JInInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
                    <constructor-arg>
                        <map>
                            <entry key="action" value="UsernameToken"></entry>
                            <entry key="passwordType" value="PasswordText"></entry>
                            <!-- 设置密码类型为加密
                            <entry key="passwordType" value="PasswordDigest" />-->
    
                            <entry key="passwordCallbackClass" value="com.ekservice.interceptor.ExampleServiceInterceptor"></entry>
                        </map>
                    </constructor-arg>
                </bean>
            </jaxws:inInterceptors>
    
            <jaxws:outInterceptors>
                <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
            </jaxws:outInterceptors>
        </jaxws:endpoint>
        
    </beans>

        <2>拦截器ExampleServiceInterceptor.java的代码,有详细注释

    package com.ekservice.interceptor;
    
    import org.apache.log4j.Logger;
    import org.apache.ws.security.WSPasswordCallback;
    import org.apache.ws.security.WSSecurityException;
    
    import javax.security.auth.callback.Callback;
    import javax.security.auth.callback.CallbackHandler;
    import javax.security.auth.callback.UnsupportedCallbackException;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    
    /** 
     * @author EK
     * @version 创建时间:2015-5-14 下午04:13:47 
     * 类说明 
     */
    public class ExampleServiceInterceptor implements CallbackHandler{
        Logger logger = Logger.getLogger(ExampleServiceInterceptor.class);
    
        private Map<String, String> passwords = new HashMap<String, String>();
        
        public ExampleServiceInterceptor() {
            passwords.put("admin", "password");
        }
        public void handle(Callback[] callbacks) throws IOException,
                UnsupportedCallbackException {
            
            for (int i = 0; i < callbacks.length; i++) {
                WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
                String identifier = pc.getIdentifier();
                int usage = pc.getUsage();
                logger.info("Client Token [username: " + identifier+", password: "+ passwords.get(identifier) + "] Exist user: "+passwords.containsKey(identifier));
                if (usage == WSPasswordCallback.USERNAME_TOKEN) {// 密钥方式USERNAME_TOKEN
                    if (!passwords.containsKey(identifier)) {
                        try {
                            throw new WSSecurityException("User not match - "+identifier);
                        } catch (WSSecurityException e) {
                            e.printStackTrace();
                        }
                    }
                    // username token pwd...
                    // ▲这里的值必须和客户端设的值相同,从cxf2.4.x后校验方式改为cxf内部实现校验,不必自己比较password是否相同
                    // 请参考:http://cxf.apache.org/docs/24-migration-guide.html的Runtime
                    // Changes片段
                    pc.setPassword(passwords.get(identifier));// ▲【这里非常重要】▲
                    // ▲PS 如果和客户端不同将抛出org.apache.ws.security.WSSecurityException:
                    // The
                    // security token could not be authenticated or
                    // authorized异常,服务端会认为客户端为非法调用
                }else if (usage == WSPasswordCallback.SIGNATURE) {// 密钥方式SIGNATURE
                    if (!passwords.containsKey(identifier)) {
                        try {
                            throw new WSSecurityException("User not match - "+identifier);
                        } catch (WSSecurityException e) {
                            e.printStackTrace();
                        }
                    }
                    // set the password for client's keystore.keyPassword
                    // ▲这里的值必须和客户端设的值相同,从cxf2.4.x后校验方式改为cxf内部实现校验,不必自己比较password是否相同;
                    // 请参考:http://cxf.apache.org/docs/24-migration-guide.html的Runtime
                    // Changes片段
                    pc.setPassword(passwords.get(identifier));// //▲【这里非常重要】▲
                    // ▲PS:如果和客户端不同将抛出org.apache.ws.security.WSSecurityException:The
                    // security token could not be authenticated or
                    // authorized异常,服务端会认为客户端为非法调用
                }
            }
        }
    
    }

          <3>接口及其实现类的代码,比较简单,只是做个示例

    package com.ekservice.service;
    
    import com.ek.entry.user.User;
    
    import javax.jws.WebMethod;
    import javax.jws.WebParam;
    import javax.jws.WebResult;
    import javax.jws.WebService;
    
    /** 
     * @author EK
     * @version 创建时间:2015-5-14 下午02:17:59 
     * 类说明 
     */
    @WebService(targetNamespace="http://jeeek-dp/", name="ExampleService")
    public interface ExampleService {
    
        @WebResult(name="password")
        @WebMethod(action="http://jeeek-dp/ExampleService/getStr")
        public User getStr(@WebParam(name="name")String userName);
    
    
        @WebMethod(action="http://jeeek-dp/ExampleService/receive")
        public void receive();
    
        @WebResult(name="tokenId")
        @WebMethod(action="http://jeeek-dp/ExampleService/getTokenId")
        public String getTokenId();
    
        @WebResult(name="sendUnitInfo")
        @WebMethod(action="http://jeeek-dp/ExampleService/getSendUnitInfo")
        public int getSendUnitInfo(@WebParam(name="orgAccountId")long orgAccountId, @WebParam(name="recOrgType")int recOrgType, @WebParam(name="recOrgId")long recOrgId);
    
    }
    package com.ekservice.impl;
    
    import com.ek.entry.user.User;
    import com.ekservice.service.ExampleService;
    import org.apache.log4j.Logger;
    
    import javax.jws.WebService;
    
    /** 
     * @author EK
     * @version 创建时间:2015-5-14 下午02:30:35 
     * 类说明 
     */
    @WebService(targetNamespace="http://jeeek-dp/", serviceName="ExampleService", name="ExampleService")
    public class ExampleServiceImpl implements ExampleService {
        Logger logger = Logger.getLogger(ExampleServiceImpl.class);
    
        public User getStr(String userName) {
            User user = new User();
            user.setAddress("北京市海淀区222号");
            user.setMobilePhone("010-1101111");
            
            System.out.println(userName+" "+user.getAddress());
            
            return user;
        }
    
    
        @Override
        public void receive() {
            this.logger.info("Call reveive() method....");
        }
    
        @Override
        public String getTokenId() {
            this.logger.info("Call getTokenId() method....");
            return "success";
        }
    
        @Override
        public int getSendUnitInfo(long orgAccountId, int recOrgType, long recOrgId) {
            this.logger.info("Call getSendUnitInfo() method...."+orgAccountId+", "+recOrgType+", "+recOrgId);
            return 0;
        }
    
    
    }

    二、客户端

        <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"  
        xsi:schemaLocation="http://www.springframework.org/schema/beans   
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
            http://cxf.apache.org/jaxws   
            http://cxf.apache.org/schemas/jaxws.xsd">
    
        <bean id="exampleServiceClientInterceptor" 
            class="com.ek.client.interceptor.ExampleServiceClientInterceptor"></bean>
        <bean id="WSS4JOutInterceptor" 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="admin" />
                    <!-- <entry key="mustUnderstand" value="false"></entry> -->
                    <entry key="passwordCallbackRef">
                        <ref bean="exampleServiceClientInterceptor" />
                    </entry>
                </map>
            </constructor-arg>
        </bean>
        <jaxws:client id="exampleService"  
            address="http://localhost:8080/jeeek-dp/services/ExampleService"
            serviceClass="com.ek.client.services.example.ExampleService">
            <jaxws:outInterceptors>  
                <bean class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor"></bean>
                <ref bean="WSS4JOutInterceptor"/>
            </jaxws:outInterceptors>
        </jaxws:client>
        
        <bean id="eperpServiceClientInterceptor" 
            class="com.ek.client.interceptor.CPERPServiceClientInterceptor"></bean>
        <bean id="cperp" 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="cpweb" />
                    <entry key="passwordCallbackRef">
                        <ref bean="eperpServiceClientInterceptor" />
                    </entry>
                </map>
            </constructor-arg>
        </bean>
        
    </beans>

        <2>客户端拦截器代码

    package com.ek.client.interceptor;
    
    import org.apache.log4j.Logger;
    import org.apache.ws.security.WSPasswordCallback;
    import org.apache.ws.security.WSSecurityException;
    
    import javax.security.auth.callback.Callback;
    import javax.security.auth.callback.CallbackHandler;
    import javax.security.auth.callback.UnsupportedCallbackException;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    
    /** 
     * @author EK
     * @version 创建时间:2015年5月15日 上午11:36:20 
     * 类说明 
     */
    public class ExampleServiceClientInterceptor implements CallbackHandler{
    
        Logger logger = Logger.getLogger(ExampleServiceClientInterceptor.class);
    
        private Map<String, String> passwords = new HashMap<String, String>();
        
        public ExampleServiceClientInterceptor() {
            passwords.put("admin", "password");
        }
        public void handle(Callback[] callbacks) throws IOException,
                UnsupportedCallbackException {
            
            for (int i = 0; i < callbacks.length; i++) {
                WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
                String identifier = pc.getIdentifier();
                int usage = pc.getUsage();
                
                if (usage == WSPasswordCallback.USERNAME_TOKEN) {// 密钥方式USERNAME_TOKEN
                    logger.info("Client Token [username: " + identifier+", password: "+ passwords.get(identifier) + "] Exist user= "+passwords.containsKey(identifier));
                    if (!passwords.containsKey(identifier)) {
                        try {
                            throw new WSSecurityException("User not match - "+identifier);
                        } catch (WSSecurityException e) {
                            e.printStackTrace();
                        }
                    }
                    pc.setPassword(passwords.get(identifier));// //▲【这里非常重要】▲
                }else if (usage == WSPasswordCallback.SIGNATURE) {// 密钥方式SIGNATURE
                    if (!passwords.containsKey(identifier)) {
                        try {
                            throw new WSSecurityException("User not match - "+identifier);
                        } catch (WSSecurityException e) {
                            e.printStackTrace();
                        }
                    }
                    pc.setPassword(passwords.get(identifier));// //▲【这里非常重要】▲
                }
            }
        }
    
    }

        <3>客户端接口代码

    package com.ek.client.services.example;
    
    import javax.jws.WebMethod;
    import javax.jws.WebParam;
    import javax.jws.WebResult;
    import javax.jws.WebService;
    import javax.xml.ws.RequestWrapper;
    import javax.xml.ws.ResponseWrapper;
    
    /**
     * 
     */
    @WebService(targetNamespace = "http://jeeek-dp/", name = "ExampleService")
    public interface ExampleService {
    
        @WebResult(name = "password", targetNamespace = "")
        @RequestWrapper(localName = "getStr", targetNamespace = "http://jeeek-dp/")
        @WebMethod(action = "http://jeeek-dp/ExampleService/getStr")
        @ResponseWrapper(localName = "getStrResponse", targetNamespace = "http://jeeek-dp/")
        public User getStr(
            @WebParam(name = "name", targetNamespace = "")
            java.lang.String name
        );
    
        
        @RequestWrapper(localName = "receive", targetNamespace = "http://jeeek-dp/")
        @WebMethod(action = "http://jeeek-dp/ExampleService/receive")
        public void receive();
    
        @WebResult(name = "tokenId", targetNamespace = "")
        @RequestWrapper(localName = "getTokenId", targetNamespace = "http://jeeek-dp/")
        @WebMethod(action = "http://jeeek-dp/ExampleService/getTokenId")
        @ResponseWrapper(localName = "getTokenIdResponse", targetNamespace = "http://jeeek-dp/")
        public java.lang.String getTokenId();
    
        @WebResult(name = "sendUnitInfo", targetNamespace = "")
        @RequestWrapper(localName = "getSendUnitInfo", targetNamespace = "http://jeeek-dp/")
        @WebMethod(action = "http://jeeek-dp/ExampleService/getSendUnitInfo")
        @ResponseWrapper(localName = "getSendUnitInfoResponse", targetNamespace = "http://jeeek-dp/")
        public java.lang.Integer getSendUnitInfo(
                @WebParam(name = "orgAccountId", targetNamespace = "")
                java.lang.Long orgAccountId,
                @WebParam(name = "recOrgType", targetNamespace = "")
                java.lang.Integer recOrgType,
                @WebParam(name = "recOrgId", targetNamespace = "")
                java.lang.Long recOrgId
        );
    
    }

         <4>客户端调用类

    package com.ek.client.call;
    
    import com.ek.client.interceptor.ExampleServiceClientInterceptor;
    import com.ek.client.services.example.ExampleService;
    import com.ek.client.services.example.User;
    import org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor;
    import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
    import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
    import org.apache.ws.security.WSConstants;
    import org.apache.ws.security.handler.WSHandlerConstants;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /** 
     * @author EK
     * @version 创建时间:2015年5月15日 上午11:05:06 
     * 类说明 
     */
    public class ExampleServiceClient {
    
        public static void main(String[] args) {
    //        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-cxf-client.xml");
    //        ExampleService es = (ExampleService) ctx.getBean("exampleService");
            Map<String, Object> map = new HashMap<String, Object>();
            map.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
            map.put(WSHandlerConstants.USER, "admin");
            map.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
            map.put(WSHandlerConstants.PW_CALLBACK_CLASS, ExampleServiceClientInterceptor.class.getName());
            
            List list = new ArrayList();
            list.add(new SAAJOutInterceptor());
            list.add(new WSS4JOutInterceptor(map));
            
            JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
            factory.setServiceClass(ExampleService.class);
            factory.setAddress("http://localhost:8080/jeeek-dp/services/ExampleService");
            factory.getOutInterceptors().addAll(list);
            ExampleService es = (ExampleService) factory.create();
            
            User u = es.getStr("ssss");
            //Integer sui = es.getSendUnitInfo(1L, 2, 3L);
            String tokenId = es.getTokenId();
            //es.receive();
    
            
            System.out.println("的, " + tokenId);
            //System.out.println("的" + sui);
        }
    }
  • 相关阅读:
    linux —— 学习笔记(汇总)
    linux —— ubuntu 初次安装问题
    更改CMD默认的初始路径
    深入浅出理解linux inode结构
    重拾简单的linux指令之info 【转】
    Python 中数据的序列化和反序列化(json处理)
    day07
    Python 的反射机制
    Python 的 __new__()方法与实例化
    Classes as objects
  • 原文地址:https://www.cnblogs.com/edi-kai/p/6549353.html
Copyright © 2011-2022 走看看