在SpringSide实现XFire Webservice认证

XFire官方网站提供的基于Webservice认证的例子有问题,在新版本的XFire1.1.2中编译不通过,不过这也是小Case,我后来折腾了一下,为SpringSide提供了一个简单的Webservice认证功能。
XFire跟Spring的天然融合,让我们可以少努力10年就能简单地在Spring中使用Webservice的强大魅力,我从AXIS专向XFire有一些冲动,也吃了不少亏,但受REST一族的强力吹捧,感觉还是值得尝试的,因此,在公司的系统中也把Axis彻底换了XFire。

回到SpringSide,我大概介绍一下如何配置一个真正实用的XFire验证服务。
SpringSide中的XFire配置文件放在:
SpringSide-bookstore\src\org\springside\bookstore\plugins\webservice\applicationContext-webservice-server.xml
我们在里面定义各个Webservice,该文件其实对应于XFire官方的XFire-Servlet.xml
看看下面的BookService,这是一个典型的Webservice服务,红色的inHandlers是我挂上去的。它的意思是所有访问BookService的请求都会被先送到 authenticationHandler去处理,我们的验证逻辑可以在里面进行。
    <!--Web Service 在SpringMVC中的URL 路径映射-->
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <value>/BookService=bookWebService</value>
        </property>
        <property name="inHandlers">
            <ref bean="authenticationHandler"/>
        </property>

    </bean>

我们接着看看 authenticationHandler的代码:
我们在SpringSide中通过header方式向服务器提供验证信息(另外一种更简单的方式是创建一个Login的webservice服务,然后在XFire Session中建立Token信息)。
package  org.springside.bookstore.plugins.webservice.authentication;

import  org.apache.log4j.Logger;
import  org.codehaus.xfire.MessageContext;
import  org.codehaus.xfire.exchange.InMessage;
import  org.codehaus.xfire.fault.XFireFault;
import  org.codehaus.xfire.handler.AbstractHandler;
import  org.jdom.Element;
import  org.jdom.Namespace;


/**
 * XFire的回调的Handler,在XFire配置文件中配置
 * Server端的认证模块,回调处理模块
 * 
 * ClientAuthHandler跟AuthenticationHandler要一起用,或者都不用
 * 
 * 
@author   david.turing
 * @blog  openssl.blogjava.net
 *
 
*/
public   class  AuthenticationHandler  extends  AbstractHandler {
    
private   static   final  Logger log  =  Logger.getLogger(AuthenticationHandler. class );
    
    
public   void  invoke(MessageContext context)  throws  Exception {
        
        log.info(
" #AuthenticationHandler is invoked " );
        InMessage message
= context.getInMessage();
        
        
final  Namespace TOKEN_NS  =  Namespace.getNamespace( " SpringSide " , " http://service.webservice.plugins.bookstore.springside.org " );  
        
        
if (message.getHeader() == null )
        {
            
throw   new  XFireFault( " GetRelation Service Should be Authenticated " ,
                    XFireFault.SENDER);
        }
        
        Element token 
=  message.getHeader().getChild( " AuthenticationToken " , TOKEN_NS);
        
if  (token  ==   null )
        {
            
throw   new  XFireFault( " Request must include authentication token. " ,
                                 XFireFault.SENDER);
        }

        String username 
=  token.getChild( " Username " , TOKEN_NS).getValue();
        String password 
=  token.getChild( " Password " , TOKEN_NS).getValue();

        System.out.println(
" username= " + username);        
        System.out.println(
" password= " + password);
        
        
if (username == null || password == null )
            
throw   new  XFireFault( " Supplied Username and Password Please " ,
                    XFireFault.SENDER);
        
        
/**
         * 检查用户名密码是否正确
         
*/
        PasswordAuthenticationManager pamanager
= new  PasswordAuthenticationManager();
        
if ( ! pamanager.authenticate(username,password))
            
throw   new  XFireFault( " Authentication Fail! Check username/password " ,
                    XFireFault.SENDER);
 
        
    }
}
注意,XFireFault异常是往客户端抛的,Webservice Client应该学会catch XFireFault.

服务器端就是这么简单,看看客户端的TestCase
package  org.springside.bookstore.plugins.webservice.service;

import  java.lang.reflect.Proxy;
import  java.net.MalformedURLException;
import  java.util.List;

import  org.codehaus.xfire.client.Client;
import  org.codehaus.xfire.client.XFireProxy;
import  org.codehaus.xfire.client.XFireProxyFactory;
import  org.codehaus.xfire.service.Service;
import  org.codehaus.xfire.service.binding.ObjectServiceFactory;
import  org.springside.bookstore.commons.domain.Book;
import  org.springside.bookstore.plugins.webservice.authentication.ClientAuthHandler;

import  junit.framework.TestCase;

public   class  BookServiceWithAuthenticationTestCase  extends  TestCase {

    
protected   void  setUp()  throws  Exception {
        
super .setUp();
    }

    
protected   void  tearDown()  throws  Exception {
        
super .tearDown();
    }
    
    
public   void  getBookFromWebservice()  throws  Exception{
    
          Service serviceModel 
=   new  ObjectServiceFactory()
                .create(BookService.
class );
        BookService service 
=   null ;
        
        
try  {
            service
= (BookService)  new  XFireProxyFactory().create(
                    serviceModel,
                    
" http://localhost:8080/springside/service/BookService " );
        } 
catch  (MalformedURLException e) {
            e.printStackTrace();
        }
        
        Client client 
=  ((XFireProxy) Proxy.getInvocationHandler(service)).getClient();
        
// 挂上ClientAuthHandler,提供认证
        client.addOutHandler( new  ClientAuthHandler());
        List list 
=  service.findBooksByCategory( null );
        assertNotNull(list);
        
for ( int  i = 0 ;i < list.size();i ++ )
            System.out.println(((Book)list.get(i)).getName());
    }

}

你应该看到上面的client.addOutHandler(new ClientAuthHandler());
没错,它跟服务器端的AuthenticationHandler是一对,一起使用的!
也就是,每个被送往WebService服务的请求都被ClientAuthHandler处理过了。
看看ClientAuthHandler做了些什么:
package  org.springside.bookstore.plugins.webservice.authentication;

import  org.apache.log4j.Logger;
import  org.codehaus.xfire.MessageContext;
import  org.codehaus.xfire.handler.AbstractHandler;
import  org.jdom.Element;
import  org.jdom.Namespace;

/**
 * 客户端端的认证模块,回调处理模块
 * 每个需要认证的WebService方法都可以挂这个Handler
 * 
 * 仅用于Demo,从解耦和易用性出发,
 * 没有跟Acegi结合,你可以任意扩展
 * 默认用户名/密码是admin/admin
 * 
 * ClientAuthHandler跟AuthenticationHandler要一起用,或者都不用
 * 
 * 
@author   david.turing
 *
 * @blog openssl.blogjava.net
 
*/     
public   class  ClientAuthHandler  extends  AbstractHandler {
        
private   static   final  Logger log  =  Logger.getLogger(ClientAuthHandler. class );
        
        
// 客户端自己配置用户名密码或者更安全的KeyStore方式
         private  String username  =   " admin " ;
        
private  String password  =   " admin " ;
        
        
public  ClientAuthHandler() {
        }
        
        
public  ClientAuthHandler(String username,String password) {
            
this .username  =  username;
            
this .password  =  password;
        }
        
        
public   void  setUsername(String username) {
            
this .username  =  username;
        }
        
        
public   void  setPassword(String password) {
            
this .password  =  password;
        }
        
        
public   void  invoke(MessageContext context)  throws  Exception {
                        
            
/** *****************************************
             * Soap Header方式
             * 从Soap Header中获取用户名密码
             ******************************************
*/
            
final  Namespace ns  =  Namespace.getNamespace( " SpringSide " , " http://service.webservice.plugins.bookstore.springside.org " );  
            Element el 
=   new  Element( " header " ,ns);

            Element auth 
=   new  Element( " AuthenticationToken " , ns);
            Element username_el 
=   new  Element( " Username " ,ns);
            username_el.addContent(username);
            Element password_el 
=   new  Element( " Password " ,ns);
            password_el.addContent(password);
            auth.addContent(username_el);
            auth.addContent(password_el);
            el.addContent(auth);            
            context.getCurrentMessage().setHeader(el);            
            log.info(
" ClientAuthHandler done! " );
        }
    }

不就是往header里面注入username,password!

在SpringSide中,所有的Spring配置文件都被小白分散到各个Module中去了,Wuyu原先是在Plugin中提供Webservice功能,因此,我仍然在Plugin中创建XFire接口。
SpringSide的Spring配置文件放在:
SpringSide-bookstore\webapp\WEB-INF\springmvc-servlet.xml
该文件定义了Plugin的xml:
AuthenticationHandler这个Bean需要先定义在Plugins-servlet.xml中,其它很简单,大家去Try一下就知道了。
package com.xfire.core.client; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.codehaus.xfire.client.XFireProxyFactory; import org.codehaus.xfire.service.Service; import org.codehaus.xfire.service.binding.ObjectServiceFactory; import com.xfire.core.entity.UserInfo; import com.xfire.core.service.IUserInfoService; /** *@author jilongliang *@Date 2012-3-5 * */ public class UserInfoClient { public static void main(String[] args) { getServiceList(); setServiceList(); } static String url = "http://localhost:8081/xfire/services/UserInfo"; /** * */ public static void getServiceList() { Service service = new ObjectServiceFactory() .create(IUserInfoService.class); try { IUserInfoService iAddressService = (IUserInfoService) new XFireProxyFactory() .create(service, url); List list = (ArrayList) iAddressService .getAddressList(); System.out.println("一共多少条数据:" + list.size()); for (Iterator iter = list.iterator(); iter.hasNext();) { UserInfo a = iter.next(); System.out.println(a); } } catch (MalformedURLException e) { e.printStackTrace(); } } public static void setServiceList() { Service service = new ObjectServiceFactory() .create(IUserInfoService.class); try { IUserInfoService iAddressService = (IUserInfoService) new XFireProxyFactory() .create(service, url); List listAdd = new ArrayList(); UserInfo address = new UserInfo(); address.setIdentifier(1); address.setCountry("中國"); address.setProivice("廣東省"); address.setCity("陽江"); address.setAddress("廣東陽春"); address.setPostCode("1111111"); address.setExist(false); address.setArrary(new String[] { "22", "23", "24" }); listAdd.add(address); address.setIdentifier(2); address.setCountry("中國"); address.setProivice("廣東省"); address.setCity("陽江"); address.setAddress(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值