`

Web Service实现的关注点分离

阅读更多

  关注点分离(separation of concerns)是面向服务的架构(Service-Oriented Architectures,SOA)的核心原则。令人遗憾的是,该原则在实现SOA服务时常常起不到作用。我们通常会看到带有多个关注点(如安全、事务管理)的巨大的实现类,使用业务逻辑记录所有混合在一起的关注点。使用Spring Framework和Aspect Oriented Programming (AOP)原则,我们可以将关注点分离,以用于服务实现。

  本文中我们将演示如何使用Apache Axis和Spring来开发Web service,并使用Acegi Security对其进行保护——同时保持关注点很好地分离。

动机和设计

  本文中我们将使用的示例是名为FundsTransferService的服务,银行使用该服务将资金从一个账户转移到另一个账户。可以在本文的参考资料部分找到该服务的WSDL及所有源代码、配置文件和构建文件。我们有意让该服务保持非常简单,以便集中讨论本文更有意义的方面。在本服务的实现中,我们将涉及三个关注点:

  • Web service管道,用来公开作为服务的功能
  • 用于转移资金的业务逻辑
  • 安全性,用于保证只有经授权的用户才能执行资金转移

  而真正的系统很可能是必须处理其他的关注点,如事务管理、日志等。

  我们想设计这样一种实现,处理每个关注点的代码与其他的代码完全分离。对于Web service管道,我们将使用Axis来公开作为服务的功能。用于将资金从一个账户转移到另一个账户的业务逻辑将封装在一组POJO(Plain Old Java Object)中。将通过Acegi Security框架来提供安全性。我们将使用Spring Framework及其AOP工具把各方面联系起来,使构成该Web service实现的所有代码之间的依赖性减到最小。

  该实现的设计如图1所示。以黄色表示的对象就是我们需要实现的Web service。以蓝色表示的对象来自Axis;以粉红色表示的对象来自Acegi;以绿色表示的对象来自Spring。FundsTransferService是WSDL中所定义的服务接口。为了简化图表,我们将所有Axis类显示为名为Axis Engine的组件。BasicHandler也是Axis类,但由于它对于设计比较重要(稍后详述),所以单独显示出来。FundsTransferServiceSoapBindingImpl是Axis的生成类,需要实现它来提供服务功能。将直接通过Spring委派业务逻辑POJO AccountMgrImpl(稍后也会对此进行详细解释)。AccountMgrImpl与AccountMgr接口捆绑在一起是不错的做法,因为这样就允许我们插入Spring以发挥其作用(尽管有其他方法可以不带接口使用Spring)。

   Web Service实现的关注点分离图-1

   图1.FundsTransferService实现的设计

  现在回到BasicHandler。需要返回的原因涉及到如何选择以提供安全。在本例中,将在两个不同级别上处理安全性:Web service的安全性,及应用程序代码的安全性,如POJO。按照关注点分离的理念,我们提出允许进行分离的设计。Axis允许插入定制的处理程序,侦听请求和响应消息,以提供其他功能(如安全性)。因此,我们将创建名为AcegiBridgeAuthenticationHandler的定制处理程序,负责处理Web service安全。将扩展Axis类BasicHandler,以便可以将其插入Axis处理程序框架。Acegi将用于提供应用程序级的安全,如提供对POJO的访问控制。

  为了使这些方面无缝工作,需要将Web service安全上下文连接到Acegi安全上下文——因此定制的Axis处理程序类的名称为AcegiBridgeAuthenticationHandler。它不仅将处理Web service安全性,还负责将从该过程获取的安全上下文连接到Acegi环境,这样Acegi就可以决定是否授权访问POJO。方法是从Web service请求消息中提取安全声明,进行验证,然后创建认证令牌,因为我们已经为本例选择了用户名/密码认证,所以为UsernamePasswordAuthenticationToken。然后将该认证令牌设置到Acegi SecurityContext中,这样稍后在控制访问业务逻辑POJO时,Acegi可以使用请求方的证书和权限。

  下面将解释如何使用Spring把各方面联系起来。法宝就是图1中名为AOP proxy的小绿色对象,由Spring生成。该对象实现了AccountMgr接口,并担当业务逻辑POJO AccountMgrImpl的代理。这允许Spring插入Acegi的MethodSecurityInterceptor,当有人尝试在POJO上调用方法时,会执行访问控制检查。当FundsTransferServiceSoapBindingImpl将Web service请求委派给POJO时,实际上是委派给AOP代理的实例,而不是直接委派给AccountMgrImpl。由于FundsTransferServiceSoapBindingImpl扩展了ServletEndpointSupport,因此它可以访问Spring应用程序上下文,以获得配置了正确接口、侦听器和目标类的AOP代理的引用AccountMgrImpl。

  图2中的序列图演示了客户端调用FundsTransferService时,将发生的处理流程。请求消息由Axis Engine接收,然后调用AcegiBridgeAuthenticationHandler。AcegiBridgeAuthenticationHandler将验证认证信息,然后创建UsernamePasswordAuthenticationToken。接着,将该令牌设置到Acegi的SecurityContext中,用于稍后使用。AcegiBridgeAuthenticationHandler成功返回后,Axis Engine将在FundsTransferServiceSoapBindingImpl上调用transferFunds()方法。FundsTransferServiceSoapBindingImpl将其委派给AOP代理,在初始化过程中,可以较早从Spring web应用程序上下文获取。AOP proxy将调用Acegi MethodSecurityInterceptor,这样就可以进行它的安全检查。MethodSecurityInterceptor从SecurityContext获取认证令牌,然后检查是否已经对其进行了认证。接下来,将使用认证令牌中的信息来确定是否应该授权客户端的访问,在AccountMgrImpl上调用transferFunds()方法。如果允许客户端进行访问,那么MethodSecurityInterceptor将允许调用该方法,然后进入AccountMgrImpl。最后AccountMgrImpl处理该请求,并返回结果,最终传送回客户端程序。

  Web Service实现的关注点分离图-2

   图2.演示服务实现处理流程的序列图。

业务逻辑实现和配置

  我们的讨论将从解释业务逻辑类的实现和配置开始,因为他们是最简单的。AccountMgr接口和AccountMgrImpl类的源代码参见参考资料。从源代码中可以发现,事实上实现并没有做任何事情,所以可以保持其简单,因为本文并不是关于如何编写转移资金代码的文章。

  下面是Spring配置文件的部分代码(可在参考资料部分得到整个配置文件),这些代码表明了如何配置业务逻辑的Spring beans,以便使用Spring的AOP工具。第一个bean条目是为AccountMgrImpl类创建bean。第二个bean条目是如何施展前面讨论的全部AOP代理魔法。使用从ProxyFactoryBean获取的id accountMgr来创建bean。当FundsTransferServiceSoapBindingImpl类向Spring请求具有该id的bean时,ProxyFactoryBean将返回AOP代理对象的实例。对它进行配置来实现AccountMgr接口,这样客户端程序会认为他们只是在使用业务逻辑对象。使用名为interceptorNames的第二个属性,创建名为securityInterceptor的bean(稍后将进行解释),可以侦听方法调用以执行安全检查。这允许我们在业务逻辑代码中插入不带任何依赖性的Acegi安全机制。最后,将目标设置到accountMgrTarget bean,这样方法调用将最终传送到实际的业务逻辑类AccountMgrImpl。

<beans>
  <bean id="accountMgrTarget"
    class="com.mybank.bizlogic.AccountMgrImpl"/>
  . . .
  <bean id="accountMgr"
    class="org.springframework.aop.framework.
    ProxyFactoryBean">
    <property name="proxyInterfaces">
      <list>
        <value>
          com.mybank.bizlogic.AccountMgr
        </value>
      </list>
    </property>
    <property name="interceptorNames">
      <list>
        <value>
          securityInterceptor
        </value>
      </list>
    </property>
    <property name="target">
      <ref bean="accountMgrTarget"/>
    </property>
  </bean>
  . . .
</beans>

Web service实现和配置

  FundsTransferServiceSoapBindingImpl类是Web service实现。其源代码请参见参考资料部分。该类的框架由Axis生成,我们仅仅填写方法来提供实现。请注意该类扩展了ServletEndpointSupport。这是Spring提供的便利类,可以用于JAX-RPC Web service实现,来获取Spring应用程序上下文的引用。通过扩展该类,FundsTransferServiceSoapBindingImpl类可以访问Spring上下文,来获取先前所描述的accountMgr bean的引用。由于FundsTransferServiceSoapBindingImpl类由Axis管理,我们无法使用Spring的依赖性注入工具来自动获取该bean的引用。因此,必须在onInit()方法中明确执行。不幸的是,这会将该类中的一些依赖性添加到特定于Spring的类中。好,这就是使用Spring和Acegi在得到受益的同时需要付出的小小代价。请注意在实际的方法transferFunds()中,代码仅委派给accountMgr bean。

  在Axis配置文件(deploy.wsddserver-config.wsdd)中,需要确保将服务的实现类设置为该类FundsTransferServiceSoapBindingImpl,而不是由Axis生成的其他框架类(FundsTransferServiceSoapBindingSkeleton)。若要使Spring在与Axis相同的web应用程序中正确地工作,我们需要将下面的条目添加到web.xml文件中。context-param条目指定了放置Spring配置文件的位置。listener条目的设置用于在启动时载入Spring配置和上下文。

<web-app>
  <context-param>
    <param-name>
      contextConfigLocation
    </param-name>
    <param-value>
      /WEB-INF/spring-config.xml
    </param-value>
  </context-param>

  <listener>
    <listener-class>
      org.springframework.web.context.
      ContextLoaderListener
    </listener-class>
  </listener>
. . .
</web-app>

Acegi安全配置

  现在我们来讨论如何在Spring配置文件中配置Acegi安全。如前所述,我们配置了业务逻辑bean,因此由securityInterceptor bean来侦听方法调用,以执行安全检查。下面我们来看看如何配置该bean。下面所示是securityInterceptor bean的部分Spring配置文件代码。securityInterceptor bean是由名为MethodSecurityInterceptor的Acegi类提供的。正如其名称所示,该类用于加强方法调用的安全,通过侦听调用并检查调用方是否经过认证和授权。

<beans>
  . . .
  <bean id="securityInterceptor"
    class="org.acegisecurity.intercept.method.
      aopalliance.MethodSecurityInterceptor">
    <property name="authenticationManager">
      <bean class="org.acegisecurity.
        providers.ProviderManager">
        <property name="providers">
          <list>
            <bean
              class="org.acegisecurity.
                providers.anonymous.
                AnonymousAuthenticationProvider">
              <property
                name="key"
                value="changeThis"/>
            </bean>
          </list>
        </property>
      </bean>
    </property>

    <property name="accessDecisionManager">
      <bean
        class="org.acegisecurity.vote.
          UnanimousBased">
        <property name="decisionVoters">
          <list>
            <bean
              class="org.acegisecurity.
                vote.RoleVoter"/>
          </list>
        </property>
      </bean>
    </property>

    <property
      name="objectDefinitionSource">
      <value>
        com.mybank.bizlogic.AccountMgr.
          transferFunds=ROLE_MANAGER
      </value>
    </property>
  </bean>
  . . .
</beans>

  我们需要配置带有authenticationManager属性的securityInterceptor bean,以指定使用哪种类型的认证。由于我们的设计依靠Axis 处理程序来执行认证,而这里不需要认证,因此仅使用AnonymousAuthenticationProvider进行配置。另外,我们在Axis处理程序中创建认证令牌的方式会使Acegi获知它已经进行了认证,因此不会尝试再次认证。稍后讨论Axis处理程序时,我们将对此进行更加详细的解释。

  接下来,我们需要配置带有accessDecisionManager属性的bean,以指定如何决定是否授权某用户进行访问以调用方法。Acegi具有访问决策管理器(access decision manager)的三个具体实现:AffirmativeBased、ConsensusBased和UnanimousBased。Acegi根据投票人对是否授权某用户进行访问以执行特定操作的投票,来实施访问策略。计算投票数来决定是否应该授权访问。我们选择了UnanimousBased访问决策管理器,为了客户端能够执行操作,需要所有的投票都授权访问。用户应该阅读Acegi文档,以获取对该访问决策的更深入说明。下面,我们必须配置带有投票人列表的accessDecisionManager。这里我们仅使用一个名为RoleVoter投票人。这是来自Acegi的类,根据基于角色访问控制对是否授权访问进行投票。用户还应参考Acegi文档,以获取对RoleVoter工作方式的更深入说明。

  需要配置的最后一个属性是objectDefinitionSource。这就是如何指定访问受保护的对象上不同方法所需要的认证。在这里,我们只想保护transferFunds()方法,并且只允许访问manager。通过列出所有符合条件的类名、方法名和进行访问所需的角色来实现:

com.mybank.bizlogic.AccountMgr.transferFunds=
  ROLE_MANAGER

定制的Axis处理程序

  如先前所描述的,我们需要某个事物来连接Web service安全上下文和Acegi安全上下文。这里即用到定制的Axis处理程序AcegiBridgeAuthenticationHandler。其源代码请参见参考资料部分。我们保持了非常简单的实现,这样易于解释。可能引起注意的第一件事情是它实际上没有进行任何认证。我们只是从MessageContext中得到用户名和密码,然后照旧使用它们。当然,事实上真正的实现将尝试验证该信息。需要考虑的事情是真正的实现应该从SOAP消息中提取WS-Security头,然后进行处理以得到认证信息,而不是像我们这样仅仅从Axis MessageContext对象中提取他们。

  得到认证信息后,接下来就是使其可用于Acegi。通过创建认证令牌,并在Acegi安全上下文中进行设置来实现。由于在进行用户名和密码认证,因此将创建UsernamePasswordAuthenticationToken的实例。进行创建前,需要指定为该主体授予了哪些权限。通过使用GrantedAuthority接口和称为GrantedAuthorityImpl的简单实现来实现。由于使用RoleVoter来进行访问决策,因此我们将进行授权的机构是角色。这里我们再次简化了实现,对其进行硬编码,授权主体manager角色,因为该角色是在POJO上调用transferFunds()方法所需要的。真正的实现可能将获取用户名和密码,然后在数据库或目录服务器中进行查找,以找到与该主体实际相关的角色。或者,在某些情况下,可在WS-Security头中以SAML声明形式获得该信息。

  在任何情况下,一旦完成,都将创建UsernamePasswordAuthenticationToken实例,传递用户名、密码和授权的角色。通过使用这种形式的构造方法(采用GrantedAuthority数组),实际上在告知Acegi此令牌已经过了认证,因此不必再次进行认证。接下来,通过在SecurityContextHolder上调用静态方法来得到SecurityContext,并将认证令牌设置到SecurityContext中。现在认证和角色信息对于Acegi是下游可用的,用于执行其安全检查。因此,我们已有效地将Web service安全上下文连接到Acegi安全上下文。

  有几件需要考虑的其他事情。首先,Acegi还提供了非常可靠的认证能力,因此不是让Axis处理程序来关注认证,可以让Acegi做这些事情。若要这样做,使用未采用GrantedAuthority数组的构造方法来创建未经认证的认证令牌。用户还需要确保配置了适当的认证提供程序,而不是使用AnonymousAuthenticationProvider。第二,Acegi不仅支持用户名/密码认证,还支持其他认证。例如,如果在进行基于PKI的认证,用户可以使用X509AuthenticationToken,而不是UsernamePasswordAuthenticationToken。

  最后,需要配置Axis,在服务的请求处理路径上包含该处理程序。通过向Axis配置文件deploy.wsddserver-config.wsdd添加以下条目来实现:

<deployment
  xmlns="http://xml.apache.org/axis/wsdd/"
  xmlns:java="http://xml.apache.org/axis/
  wsdd/providers/java">

  <service name="FundsTransferService"
    provider="java:RPC" style="document"
    use="literal">
    . . .
    <requestFlow>
      <handler type="java:com.mybank.security.
        AcegiBridgeAuthenticationHandler"/>
    </requestFlow>
    . . .
  </service>
</deployment>

结束语

  关注点分离是开发面向服务的架构的关键原则。但是,它不仅需要应用到架构级,还需要应用到实现级。在本文中,我们演示了如何使用Axis、Spring和Acegi来实现符合SOA原则的受保护Web service。如示例代码所示,使用该方法使处理每个服务关注点的代码中的交叉依赖性减至最小。我们所给出的示例是刻意保持简单的,但应将其作为基础,用于开发具有可靠安全机制(结合了Web service安全性和Acegi提供的应用程序级安全性)的Web service。如前所述,真正的系统很可能需要开发处理程序,用来处理WS-Security头并将它们连接到Acegi安全上下文。一种方法是采用Apache工具包WSS4J,然后扩展其Axis处理程序以填充Acegi安全上下文,如本文所述。可能需要进行一些其他工作来创建捕获Acegi安全异常的Axis出站处理程序,并创建返回到客户端的更有意义的SOAP错误。

分享到:
评论

相关推荐

    Web Service实现SOA的关注点分离

    5. **关注点分离实现**:通过自定义的Axis处理程序BasicHandler和AcegiBridgeAuthenticationHandler,实现了Web服务级别的安全性与应用程序级别的安全性。AcegiBridgeAuthenticationHandler负责在Web服务和Acegi ...

    ASP .NET 与 Web Service 实例剖析

    ASP.NET还提供了Model-View-Controller (MVC) 模式,鼓励分离关注点和可测试的代码。 Web Service则提供了一种松耦合的方式,使得应用程序可以跨平台共享数据和服务。通过SOAP消息,Web Service可以在HTTP上交换...

    使用Ajax和Web Service重构网上书店(Ajax Web Service)指导学习

    通过以上知识点的学习和实践,开发者可以有效地将Ajax和Web Service应用于网上书店重构,实现前后端分离,提高网站性能,为用户提供更加流畅、个性化的购物体验。同时,随着技术的不断进步,开发者还需要关注新的...

    NET平台下Web Service与SQL Server2000的交互通信.pdf

    这些知识点涉及到Web Service的工作原理、关键技术和应用实践,以及.NET平台对Web Service的支持。同时,还介绍了在.NET环境下如何使用***访问SQL Server数据库,并通过Web Service实现企业间的数据交互和处理。XML...

    Eclipse下基于Axis2的Web Service平台搭建与使用

    【Eclipse下基于Axis2的Web Service平台搭建与使用】涉及多个IT领域的知识点,以下是详细的说明: 1. **Web Service**:Web Service是一种基于网络的、分布式的模块化组件,它提供了一种标准的方式,使得不同的应用...

    ASP.NET与Web Service实例剖析中文版

    1. **ASP.NET MVC**:Model-View-Controller设计模式,鼓励分离关注点和可测试性,适合大型、复杂的web应用开发。 2. **Web Forms**:基于控件的模型,适合快速开发,提供了与桌面应用程序类似的事件处理机制。 3. *...

    车票联网查询系统Web Service提供接口的方式实现

    车票联网查询系统是现代交通服务中不可或缺的一部分,它通过Web Service接口的提供,实现了全国范围内的火车票信息查询和销售。这样的系统设计主要是为了确保数据的安全性,并且能够高效地服务于众多的代销点。下面...

    RESTful Web Service 课件下载.pdf

    ### RESTful Web Service 课程知识点概述 #### 一、REST简介 REST(Representational State Transfer)是一种用于构建软件应用程序的设计风格或架构模式,它利用现有的网络标准和技术来创建灵活、可扩展的服务。...

    用于IDEAL开发web service的springframe框架的jar包

    它可以将这些关注点从核心业务逻辑中分离出来,提高代码的复用性和模块化。 3. **Spring MVC**:作为Spring的一部分,Spring MVC是一个用于构建Web应用程序的模型-视图-控制器(MVC)框架。它简化了Web应用程序的...

    一个用service-to-work设计模式实现的商品入库系统(源代码)

    通过这个商品入库系统,我们可以学习如何在Java环境中运用Service-to-Work模式,包括如何组织代码结构、如何通过接口定义业务边界、以及如何分离关注点以提升代码质量。此外,还可以研究如何使用JSP创建用户界面,...

    智能家居远程Web管理平台的设计和实现.pdf

    该论文可能总结了智能家居远程Web管理平台设计和实现过程中的关键技术和创新点,并对智能家居行业未来的发展趋势进行了展望。 由于论文内容复杂且涉及众多技术细节,本篇回答仅对提供的部分内容进行了概述,无法...

    Visual Studio 2010 Service pack 1.zip

    2. ASP.NET MVC 3支持:SP1包含了对ASP.NET Model-View-Controller 3框架的支持,这是微软推荐的Web应用程序开发模式,它鼓励清晰的分离关注点,提高了代码的可测试性和可维护性。 三、其他改进 1. 代码编辑器:...

    -web-Dao-Service-Controller--master.zip

    这种分离关注点的方式使得代码更加模块化,易于维护。 再来看-mvc-,这是一个设计模式,用于解耦用户界面、业务逻辑和数据模型。在Java后端,Controller接收并处理来自用户的请求,Service层处理业务逻辑,而Dao...

    Java Web从入门到精通_PPT

    以下是这个主题中可能包含的一些关键知识点: 1. **Java基础**:学习Java Web前,首先需要对Java编程语言有深入理解,包括语法、面向对象编程、异常处理、集合框架等。 2. **Servlet和JSP**:Servlet是Java Web...

    Java Web编程 web工作原理

    Spring MVC是Java Web中广泛采用的实现方式,它分离了业务逻辑、数据处理和用户界面,提高了代码的可维护性和可扩展性。 此外,JSP(Java Server Pages)是另一种创建动态Web内容的方式,它允许在HTML中嵌入Java...

    Java Web 整合开发 完全自学手册 源代码

    2. **MVC架构模式**:Model-View-Controller模式在Java Web中广泛应用,有助于实现业务逻辑、数据模型和用户界面的分离。了解Spring MVC或Struts等框架如何实现这一模式,提高开发效率和代码可维护性。 3. **JDBC与...

    java web 使用SSM框架实现 心理反馈系统.zip

    DI使得我们可以松耦合地创建和管理对象,而AOP则用于实现跨切面的关注点,如日志记录、事务管理等。 2. **SpringMVC框架**:Spring MVC是Spring框架的一个模块,用于处理Web应用程序的请求-响应模型。它将业务逻辑...

    fastdfs的web程序

    在Java环境下,我们可以利用FastDFS开发Web应用程序,实现文件的上传、下载和删除等功能,极大地提高了文件管理的效率。下面将详细探讨FastDFS的Web运用及其核心知识点。 首先,`pom.xml`是Maven项目的核心配置文件...

    Service层和DAO层解析

    总的来说,Service层和DAO层是软件设计中用于分离关注点的重要工具,它们帮助我们构建可维护、可扩展的系统。在设计时,需要根据项目特点灵活选择架构,确保代码的清晰性和可读性,同时也要考虑团队协作和未来可能的...

Global site tag (gtag.js) - Google Analytics