`
kong0itey
  • 浏览: 306042 次
社区版块
存档分类
最新评论

《Spring Security3》第五章第三部分翻译(保护业务层)

阅读更多

保护业务层

         到目前为止,在本书中我们的关注点都主要在 JBCP Pets 应用 web 层面的安全。但是,在实际的安全系统规划中,对服务方法应该给予同等的重视,因为它们能够访问系统中最重要的部分——数据。

         Spring Security 支持添加授权层(或者基于授权的数据处理)到应用中所有 Spring 管理的 bean 中。尽管很多的开发人员关注层的安全,其实业务层的俄安全同等主要,因为恶意的用户可能会穿透 web 层,能够通过没有 UI 的前端访问暴露的服务,如使用 web service

 

         让我们查看下面的图以了解我们将要添加安全层的位置:



 Spring Security 有两个主要技术以实现方法的安全:

l  事先授权( Pre-authorization )保证在执行一个方法之前需要满足特定的要求——例如,一个用户要拥有特定的 GrantedAuthority ,如 ROLE_ADMIN 。不能满足声明的条件将会导致方法调用失败;

l 事后授权( Post-authorization )保证在方法返回时,调用的安全实体满足声明的条件。这很少被使用,但是能够在一些复杂交互的业务方法周围提供额外的安全层。         

          事先和事后授权在面向对象设计中提供了所谓的前置条件和后置条件( preconditions and postconditions )。前置条件和后置条件允许开发者声明运行时的检查,从而保证在一个方法执行时特定的条件需要满足。在安全的事前授权和事后授权中,业务层的开发人员需要对特定的方法确定明确的安全信息,并在接口或类的 API 声明中添加期望的运行时条件。正如你可能想象的那样,这需要大量的规划以避免不必要的影响。

         

保护业务层方法的基本知识

         让我们以 JBCP Pets 中业务层的几个方法为例阐述怎样为它们应用典型的规则。

         我们对 JBCP Pets 的基础代码进行了重新组织以实现三层的设计,作为修改的一部分我们抽象出了前面章节已经介绍到的修改密码功能到业务层。不同于用 web MVC 的控制器直接访问 JDBC DAO ,我们选择插入一个业务服务以提供要求的附加功能。下图对此进行了描述:


 

我们能够看到在例子中 com.packtpub.springsecurity.service.IuserService 接口代表了应用架构的业务层,而这对我们来说,是一个合适位置来添加方法级的安全。

添加 @PreAuthorize 方法注解

         我们第一个的设计决策就是要在业务层上添加方法安全,以保证用户在修改密码前已经作为系统的合法用户进行了登录。这通过为业务接口方法定义添加一个简单的注解来实现,如下:

 

Java代码  收藏代码
  1. public   interface  IUserService {  
  2.   @PreAuthorize ( "hasRole('ROLE_USER')" )  
  3.   public   void  changePassword(String username, String password);  
  4. }  

 这就是保证合法、已认证的用户才能访问修改密码功能所要做的所有事情。 Spring Security 将会使用运行时的面向方面编程的切点( aspect oriented programming (AOP) pointcut )来对方法执行 before advice ,并在安全要求未满足的情况下抛出 AccessDeniedException 异常。

 

Spring Security 能够使用方法注解

         我们还需要在 dogstore-security.xml 中做一个一次性的修改,通过这个文件我们已经进行了 Spring Security 其他的配置。只需要在 <http> 声明之前,添加下面的元素即可:

 

Xml代码  收藏代码
  1. < global-method-security   pre-post-annotations = "enabled" />   
 

 

校验方法安全

         不相信如此简单?那我们将 ROLE_USER 声明修改为 ROLE_ADMIN 。现在用用户 guest (密码 guest )登录并尝试修改密码。你会在尝试修改密码时,看到如下的出错界面:



 如果查看 Tomcat 的控制台,你可以看到很长的堆栈信息,开始是这样的:

 

Java代码  收藏代码
  1. DEBUG - Could not complete request  
  2. o.s.s.access.AccessDeniedException: Access is denied  
  3. at o.s.s.access.vote.AffirmativeBased.decide  
  4. at o.s.s.access.intercept.AbstractSecurityInterceptor.beforeInvocation  
  5. ...  
  6. at $Proxy12.changePassword(Unknown Source)  
  7. at com.packtpub.springsecurity.web.controller.AccountController.  
  8. submitChangePasswordPage  

          基于访问拒绝的页面以及指向 changePassword 方法的堆栈信息,我们可以看到用户被合理的拒绝对业务方法的访问,因为缺少 ROLE_ADMIN GrantedAuthority 。你可以测试修改密码功能对管理员用户依旧是可以访问的。

 

         我们只是在接口上添加了简单的声明就能够保证方法的安全,这是不是太令人兴奋了?当然,我们不会愿意 Tomcat 原生的 403 错误页面在我们的产品应用中出现——我们将会在第六章:高级配置与扩展 讲述访问拒绝处理时,对其进行更新。

         让我们介绍一下实现方法安全的其它方式,然后进入功能的背后以了解其怎样以及为什么能够生效。

 

几种实现方法安全的方式

         除了 @PreAuthorize 注解以外,还有几种其它的方式来声明在方法调用前进行授权检查的需求。我们会讲解这些实现方法安全的不同方式,并比较它们在不同环境下的优势与不足。

遵守 JSR-250 标准规则

         JSR-250, Common Annotations for the Java Platform 定义了一系列的注解,其中的一些是安全相关的,它们意图在兼容 JSR-250 的环境中很方便地使用。 Spring 框架从 Spring 2.x 释放版本开始就兼容 JSR-250 ,包括 Spring Security 框架。

         尽管 JSR-250 注解不像 Spring 原生的注解富有表现力,但是它们提供的注解能够兼容不同的 Java EE 应用服务器实现如 Glassfish ,或面向服务的运行框架如 Apache Tuscany 。取决于你应用对轻便性的需求,你可能会觉得牺牲代码的轻便性但减少对特定环境的要求是值得的。

         要实现我们在第一个例子中的规则,我们需要作两个修改,首先在 dogstore-security.xml 文件中:

 

Xml代码  收藏代码
  1. < global-method-security   jsr250-annotations = "enabled" />   

 其次, @PreAuthorize 注解需要修改成 @RolesAllowed 注解。正如我们可能推断出的那样, @RolesAllowed 注解并不支持 SpEL 表达式,所以它看起来很像我们在第二节中提到的 URL 授权。我们修改 IuserService 定义如下:

 

Java代码  收藏代码
  1. @RolesAllowed ( "ROLE_USER" )  
  2. public   void  changePassword(String username, String password);  

 正如前面的练习那样,如果不相信它能工作,尝试修改 ROLE_USER ROLE_ADMIN 并进行测试。

 

         要注意的是,也可以提供一系列允许的 GrantedAuthority 名字,使用 Java 5 标准的字符串数组注解语法:

 

Java代码  收藏代码
  1. @RolesAllowed ({ "ROLE_USER" , "ROLE_ADMIN" })  
  2. public   void  changePassword(String username, String password);  

          JSR-250 还有两个其它的注解: @PermitAll @DenyAll 。它们的功能正如你所预想的,允许和禁止对方法的任何请求。

【类层次的注解。注意方法级别的安全注解也可以使用到类级别上!如果提供了方法级别的注解,将会 覆盖类级别的注解。如果业务需要在整个类上有安全策略的话,这会非常有用。要注意的是使用这个功能要有良好的注释的编码规范,这样开发人员能够很清楚的了 解类和方法的安全特性。】

         我们将会在本章稍后的练习中介绍如何实现 JSR-250 风格的注解与 Spring Security 风格 的注解并存。

@Secured 注解实现方法安全

         Spring 本身也提供一个简单的注解,类似于 JSR-250 @RolesAllowed 注解。 @Secured 注解在功能和语法上都与 @RolesAllowed 一致。唯一需要注意的不同点是要使用这些注解的话,要在 <global-method-security> 元素中明确使用另外一个属性:

 

Xml代码  收藏代码
  1. < global-method-security   secured-annotations = "enabled" />   

 因为 @Secured JSR 标准的 @RolesAllowed 注解在功能上一致,所以并没有充分的理由在新代码中使用它,但是它能够在 Spring 的遗留代码中运行。

使用 Aspect Oriented Programming AOP )实现方法安全

         实现方法安全的最后一项技术也可能是最强大的方法,它还有一个好处是不需要修改源代码。作为替代,它使用面向方面的编程方式为一个方法或方法集合声明切点( pointcut ),而增强( advice )会在切点匹配的情况下进行基于角色的安全检查。 AOP 的声明只在 Spring Security XML 配置文件中并不涉及任何的注解。

         以下就是声明保护所有的 service 接口只有管理权限才能访问的例子:

 

Xml代码  收藏代码
  1. < global-method-security >   
  2.   < protect-pointcut   access = "ROLE_ADMIN"    
  3. expression = "execution(* com.packtpub.springsecurity.service.I*Service.*(..))" />   
  4. </ global-method-security >   

 切点表达式基于 Spring AOP AspectJ 的支持。但是, Spring AspectJ AOP 仅支持 AspectJ 切点表达式语言的一个很小子集——可以参考 Spring AOP 的文档以了解其支持的表达式和其它关于 Spring AOP 编程的重要元素。

         注意的是,可以指明一系列的切点声明,以指向不同的角色和切点目标。以下的就是添加切点到 DAO 中一个方法的例子:

 

Xml代码  收藏代码
  1. < global-method-security >   
  2.   < protect-pointcut   access = "ROLE_USER"    
  3. expression ="execution(* com.packtpub.springsecurity.dao.IProductDao.getCategories(..)) &amp;&amp;  
  4. args()"/>   
  5.   < protect-pointcut   access = "ROLE_ADMIN"   expression ="execution(* com.  
  6. packtpub.springsecurity.service.I*Service.*(..))"/>   
  7. </ global-method-security >   

 注意在新增的切点中,我们添加了一些 AspectJ 的高级语法,来声明 Boolean 逻辑以及其它支持的切点,而参数可以用来确定参数的类型声明。

         Spring Security 其它允许一系列安全声明的地方一样, AOP 风格的方法安全是按照从顶到底的顺序进行的,所以需要按照最特殊到最不特殊的顺序来写切点。

         使用 AOP 来进行编程即便是经验丰富的开发人员可能也会感到迷惑。如果你确定要使用 AOP 来进行安全声明,除了 Spring AOP 的参考手册外,强烈建议你参考一些这个专题相关的书籍。 AOP 实现起来比较复杂,尤其是在解决不按照你预期运行的配置错误时更是如此。

比较方法授权的类型

         以下的快速参考表可能在你选择授权方法检查时派上用场:

        

方法授权类型

声明方式

JSR 标准

允许 SpEL 表达式

@PreAuthorize

@PostAuthorize

注解

No

Yes

@RolesAllowed

@PermitAll

@DenyAll

注解

Yes

NO

@Secure

注解

No

No

protect-pointcut

XML

No

No

         大多数使用 Java 5 Spring Security 用户倾向于使用 JSR-250 注解,以达到在 IT 组织间最大的兼容性和对业务类(以及相关约束)的重用。在需要的地方,这些基本的声明能够被 Spring Security 本身实现的注解所代替。

         如果你在不支持注解的环境中( Java 1.4 或更早版本)中使用 Spring Security ,很不幸的是,关于方法安全的执行你的选择可能会很有限。即使在这样的情况下,对 AOP 的使用也提供了相当丰富的环境来开发基本的安全声明。

方法的安全保护是怎样运行的?

         方法安全的访问决定机制——一个给定的请求是否被允许——在概念上与 web 请求的访问决定逻辑是相同的。 AccessDecisionManager 使用一个 AccessDecisionVoters 集合,其中每一个都要对能否进行访问做出允许、拒绝或者弃权的的投票。 AccessDecisionManager 汇集这些投票器的结果并形成一个最终能否允许处罚方法的决定。

         Web 请求的访问决策没有这么复杂,这是因为通过 ServletFilters 对安全请求做拦截(以及请求拒绝)都相对很直接。因为方法的触发可能发生在任何的地方,包括没有通过 Spring Security 直接配置的代码, Spring Security 的设计者于是选择 Spring 管理的 AOP 方式来识别、评估以及保护方法的触发。

         下图在总体上展现了方法触发授权决策的主要参与者:



          我们能够看到 Spring Security o.s.s.access.intercept.aopalliance.MethodSecurityInterceptor 被标准的 Spring AOP 运行时触发以拦截感兴趣的方法调用。通过上面的流程图,是否允许方法调用的逻辑就相对很清晰了。

         此时,我们可能会比较关心方法安全功能的性能。显然, MethodSecurityInterceptor 不能在应用中每个方法调用的时候触发——那方法或类上的注解是如何做到 AOP 拦截的呢?

         首先, AOP 织入默认不会对所有 Spring 管理的 bean 触发。相反,如果 <global-method-security> Spring Security 配置中定义,一个标准的 Spring AOP   o.s.beans.factory.config.BeanPostProcessor 将会被注册,它将会探查 AOP 配置是否有 AOP 增强器( advisors )需要织入(以及拦截)。这个工作流是 Spring 标准的 AOP 处理(名为 AOP 自动织入),并不是 Spring Security 所特有的。所有的 BeanPostProcessors spring ApplicationContext 初始化时执行,在所有的 Spring Bean 配置生效后。

         Spring AOP 自动织入功能查询所有注册的 PointcutAdvisors ,查看是否有 AOP 切点匹配方法的调用并使用 AOP 增强( advice )。 Spring Security 实现了 o.s.s.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor 类,它会检查所有配置的方法安全病建立适当的 AOP 拦截。注意的是,只有声明了方法安全的接口和类才会被 AOP 代理。

【强烈建议在接口上声明 AOP 规则(以及其它的安全注解),而不是在实现类上。使用类(通过 Spring CGLIB 代理)进行声明可能会导致应用出现不可预知的行为改变,通常在正确性方面比不上在接口定义安全声明(通过 AOP )。】

MethodSecurityMetadataSourceAdvisor AOP 影响方法行为的决定委托给 o.s.s.access.method.MethodSecurityMetadataSource 的实例。不同的方法安全注解都拥有自己的 MethodSecurityMetadataSource ,它将用来检查每个方法和类并添加在运行时执行的增强( advice )。

以下的图展现了这个过程是如何发生的:



          取决于你的应用中配置的 Sprin Bean 的数量,以及拥有的安全方法注解的数量,添加方法安全代理将会增加初始化 ApplicationContext 的时间。但是,一旦上下文初始化完成,对单个的代理 bean 来说性能的影响可以忽略不计了。

分享到:
评论

相关推荐

    Spring Security3中文文档

    ### 第五章:授权与业务层保护 这里讲解了如何实现精细的权限控制,包括页面级权限的实现、业务层的安全保护以及方法级别的安全控制。这部分内容对于构建高度安全的应用程序至关重要。 ### 第六章:自定义安全组件...

    《Spring Security3》第二章第三部分翻译(下)附前两章doc文档

    《Spring Security3》第二章第三部分的翻译下篇主要涵盖了Spring Security的核心概念和技术,这部分内容是深入理解Spring Security架构和实现安全控制的关键。在本章节中,我们将详细探讨以下几个核心知识点: 1. *...

    spring security3 中文版本

    自此之后,Spring Security 成为了 Spring 生态系统中的一个重要组成部分,不断迭代更新,以适应不断变化的安全需求和技术发展。 ##### 1.3 发行版本号 Spring Security 3.0.1 是在 Spring Security 3.0 的基础上...

    Spring Security in Action

    Spring Security 的架构主要包括以下几层: * Presentation Layer:负责用户交互,例如登录、登出等。 * Application Layer:负责业务逻辑,例如身份验证、授权等。 * Infrastructure Layer:负责基础设施,例如...

    Spring Security 资料合集

    - Spring Security 可以与OAuth2框架集成,提供第三方服务的认证和授权,支持资源服务器、认证服务器和客户端的角色。 8. **Spring Security ACL**: - 对象级权限管理(ACL)允许开发者对应用内的具体对象实施细...

    springSecurity3例子

    - Spring Security 3引入了CSRF(跨站请求伪造)防护,通过添加一个不可预测的令牌到表单提交中,防止恶意第三方发起未经授权的操作。 5. **国际化支持**: - 支持多语言界面,可以根据用户的首选语言显示错误...

    Spring Security-3中文官方文档(及教程)

    7. **OAuth2整合**:Spring Security可以与OAuth2框架集成,支持第三方身份验证服务,如Google、Facebook等,实现社交登录功能。 8. **Web安全**:文档涵盖了HTTP基本认证、表单登录、HTTP方法转换、XSS防护、点击...

    spring security 官方文档

    5. **CSRF保护(Cross-Site Request Forgery)**:默认情况下,Spring Security提供了对CSRF攻击的防护,通过生成和验证CSRF令牌来确保只有合法的请求才能执行。 6. **Web安全(Web Security)**:对于基于Servlet...

    Spring Security3

    ### Spring Security3 相关知识点概述 #### 第一章:一个不安全应用的剖析 **安全审计** - **目的**:识别系统中的安全隐患,并评估安全措施的有效性。 - **过程**:通过模拟攻击来测试系统的安全性,分析日志记录...

    SpringSecurity笔记,编程不良人笔记

    - OAuth2:SpringSecurity支持OAuth2协议,实现第三方登录和API保护。 - JWT(JSON Web Tokens):可使用JWT进行状态less的认证,提高系统的可扩展性。 - CORS(Cross-Origin Resource Sharing):SpringSecurity...

    springsecurity学习笔记

    7. **OAuth2 and JWT支持**:Spring Security 提供了对OAuth2和JSON Web Tokens (JWT) 的支持,这在现代微服务架构中非常重要,因为它允许第三方应用安全地与你的服务进行交互。 8. **表达式语言(SpEL)**:Spring...

    springSecurity3中文文档

    第二章:springsecurity起步 第三章:增强用户体验 第四章:凭证安全存储 第五章:精确的访问控制 第六章:高级配置和扩展 第七章:访问控制列表(ACL) 第八章:对OpenID开放 第九章:LDAP目录服务 第十章:使用...

    spring security 3.x第五章例子

    Spring Security 是一个强大的和高度可定制的身份验证和...总的来说,Spring Security 3.x第五章的实例将帮助开发者深入理解这个框架的使用,通过具体的代码示例来实践安全性配置,从而更好地保护他们的Spring应用。

    SpringSecurity素材.rar

    9. **OAuth2整合**:如果视频内容深入,可能会涉及到如何集成SpringSecurity与OAuth2服务提供商,实现第三方登录功能。 10. **安全最佳实践**:最后,可能会分享一些安全编码的最佳实践,例如避免SQL注入、XSS攻击...

    《Spring Security3》第四章第四部分翻译(Remember me后台存储和SSL)附前四章doc文件

    《Spring Security3》第四章第四部分主要探讨了Remember me服务的后台存储机制以及如何结合SSL(Secure Sockets Layer)来增强应用的安全性。这一部分的知识点涵盖了Spring Security中Remember me的功能,用户身份...

    Spring Security 教程(Spring Security Tutorial)1

    - Spring Security 不仅仅关注URL级别的访问控制,还可以在方法级别实现安全控制,这样可以在业务逻辑层细化权限管理。 5. **基于角色的登录**: - 用户登录后,Spring Security 可以根据用户的角色分配不同的...

    spring security 入门经典教程

    - 第5章:服务层安全,讲解如何保护应用的服务层,确保业务逻辑的安全性。 - 第6章:配置替代认证提供者,这一章节可能讨论了如何集成不同的认证机制,例如使用LDAP或OAuth等。 - 第7章:使用ACL实现业务对象安全...

    spring security第一个项目

    在“spring security第一个项目”中,我们将探讨如何搭建一个基础的Spring Security环境,实现用户登录验证以及权限控制。 首先,我们需要理解Spring Security的基本架构。它由四个主要组件组成:Filter Security ...

    SpringMVC集成SpringSecurity

    5. **SpringSecurity配置**:在SpringSecurity配置文件中,我们需要定义`&lt;http&gt;`元素来配置URL保护策略,`&lt;authentication-manager&gt;`元素来定义认证机制,例如使用`&lt;user-service&gt;`元素配置内存中的用户信息。...

Global site tag (gtag.js) - Google Analytics