David.Turing's blog

           

          在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一下就知道了。

          posted on 2006-07-25 23:48 david.turing 閱讀(8778) 評論(4)  編輯  收藏 所屬分類: Security領域

          評論

          # re: 在SpringSide實現XFire Webservice認證 2006-11-08 08:55 jcjack

          我有點不清楚的地方,想請教下,你的文章一再強調:
          ClientAuthHandler跟AuthenticationHandler要一起用,或者都不用。
          假如我提供一個web service面對不人的用戶,它們用可能使用java\ c#\ASP.....其他語言來中客戶端,這樣還有效果嗎?  回復  更多評論   

          # re: 在SpringSide實現XFire Webservice認證 2007-05-14 15:04 freshman

          謝謝能踢過這個xfire的例子,我try了一下,很不錯,但如果客戶端是axis實現的話怎么辦?好像得到授權。axis里面也有handler的方式進行認證,但和xfire是不是不兼容?如果是c#呢?摟主能否再指點一二?  回復  更多評論   

          # re: 在SpringSide實現XFire Webservice認證 2007-08-24 21:52 ianwong

          謝謝david,我按照你的文章已經調通.
          我想如果是采用其他語言來開發客虎端的話,只需要傳遞soapheader,里面含有相同命名空間的用戶密碼就行了吧.  回復  更多評論   

          # re: 在SpringSide實現XFire Webservice認證[未登錄] 2008-01-05 11:30 jason

          Service serviceModel = new ObjectServiceFactory()
          .create(BookService.class);
          在創建客戶端的服務時,create(class)的參數BookService是從哪里來的呢?  回復  更多評論   

          導航

          統計

          常用鏈接

          留言簿(110)

          我參與的團隊

          隨筆分類(126)

          隨筆檔案(155)

          文章分類(9)

          文章檔案(19)

          相冊

          搜索

          積分與排名

          最新隨筆

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 孟村| 利川市| 泰州市| 内江市| 都江堰市| 南丹县| 桂林市| 石柱| 宝清县| 青海省| 木兰县| 新丰县| 井研县| 清水县| 龙口市| 通许县| 邻水| 稻城县| 天峻县| 绿春县| 肃南| 平顺县| 米泉市| 盐池县| 澄城县| 封丘县| 拜泉县| 赤城县| 深水埗区| 黄龙县| 界首市| 古交市| 双流县| 郑州市| 山丹县| 高淳县| 简阳市| 神池县| 平湖市| 兰州市| 高阳县|