在springside实现xfire webservice认证 -凯发k8网页登录

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

回到springside,我大概介绍一下如何配置一个真正实用的xfire验证服务。
springside中的xfire配置文件放在:
-bookstore\src\org\springside\bookstore\plugins\webservice\applicationcontext-webservice-server.xml
我们在里面定义各个webservice,该文件其实对应于xfire官方的xfire-servlet.xml
看看下面的bookservice,这是一个典型的webservice服务,红色的inhandlers是我挂上去的。它的意思是所有访问bookservice的请求都会被先送到authenticationhandler去处理,我们的验证逻辑可以在里面进行。
    
   
       
            /bookservice=bookwebservice
       

       
           
       

   


我们接着看看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("","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("","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配置文件放在:
-bookstore\webapp\web-inf\springmvc-servlet.xml
该文件定义了plugin的xml:
authenticationhandler这个bean需要先定义在plugins-servlet.xml中,其它很简单,大家去try一下就知道了。

posted on 2006-07-25 23:48 david.turing 阅读(8700) 评论(4)     所属分类: security领域

# re: 在springside实现xfire webservice认证 2006-11-08 08:55

我有点不清楚的地方,想请教下,你的文章一再强调:
clientauthhandler跟authenticationhandler要一起用,或者都不用。
假如我提供一个web service面对不人的用户,它们用可能使用java\ c#\asp.....其他语言来中客户端,这样还有效果吗?  回复     

# re: 在springside实现xfire webservice认证 2007-05-14 15:04

谢谢能踢过这个xfire的例子,我try了一下,很不错,但如果客户端是axis实现的话怎么办?好像得到授权。axis里面也有handler的方式进行认证,但和xfire是不是不兼容?如果是c#呢?搂主能否再指点一二?  回复     

# re: 在springside实现xfire webservice认证 2007-08-24 21:52

谢谢david,我按照你的文章已经调通.
我想如果是采用其他语言来开发客虎端的话,只需要传递soapheader,里面含有相同命名空间的用户密码就行了吧.  回复     

# re: 在springside实现xfire webservice认证[未登录] 2008-01-05 11:30

service servicemodel = new objectservicefactory()
.create(bookservice.class);
在创建客户端的服务时,create(class)的参数bookservice是从哪里来的呢?  回复     

导航

统计

常用链接

留言簿(109)

我参与的团队

随笔分类(126)

随笔档案(155)

文章分类(9)

文章档案(19)

相册

搜索

积分与排名

最新随笔

最新评论

阅读排行榜

评论排行榜

网站地图