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

《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 来说性能的影响可以忽略不计了。

分享到:
评论

相关推荐

    springSecurity3中文文档

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

    spring security 3.x第五章例子

    spring security 3.x第五章例子

    spring security 参考手册中文版

    第三部分 测试 97 11.测试方法安全性 97 11.1安全测试设置 98 11.2 @WithMockUser 98 11.3 @WithAnonymousUser 100 11.4 @用户详细信息 101 11.5 @WithSecurityContext 102 11.6测试元注释 104 12. Spring MVC测试...

    Spring攻略PDF版

     第5章 动态代理和经典的Spring AOP   第6章 Spring 2.x AOP和AspectJ支持  第二部分 基础主题  第7章 Spring对JDBC的支持   第8章 Spring中的事务管理   第9章 Spring对ORM的支持   第10章...

    Spring攻略中文版PDF

     第5章 动态代理和经典的Spring AOP   第6章 Spring 2.x AOP和AspectJ支持  第二部分 基础主题  第7章 Spring对JDBC的支持   第8章 Spring中的事务管理   第9章 Spring对ORM的支持   第10章...

    Spring攻略英文版(附带源码)

     第5章 动态代理和经典的Spring AOP   第6章 Spring 2.x AOP和AspectJ支持  第二部分 基础主题  第7章 Spring对JDBC的支持   第8章 Spring中的事务管理   第9章 Spring对ORM的支持   第10章 ...

    spring security 登录、权限管理配置

    登录流程 1)容器启动(MySecurityMetadataSource:loadResourceDefine加载系统资源与权限列表) ... 执行第6步,否则执行第7步。 6)登录 7)验证并授权(MyUserDetailServiceImpl:loadUserByUsername) 内附完整数据库

    security:Spring Security 开发安全的REST服务 —— JoJozhai

    第3章 使用Spring MVC开发RESTful API 3-4 用户创建请求 3-5 修改和删除请求 3-6 服务异常处理 3-7 使用切片拦截REST服务 3-8 使用Filter和Interceptor拦截REST服务 3-9 使用REST方式处理文件服务 3-10 使用...

    SpringCloud视频教程全套百度网盘

    第4章 SpringSecurity安全详细讲解及应用 第5章 RabbitMQ高级消息的讲解及应用 第6章 ElasticSearch详细讲解及应用 第7章 Eureka分布式服务器的搭建 。。。。。。。。。 第15章 SpringCloud项目实战 。。。。。。。...

    Spring攻略(第三版)源代码

    3. Spring Annotation Driven Core Tasks 4. Spring @MVC 5. Spring REST 6. Spring Deployment to the Cloud 7. Spring Social 8. Spring Security 9. Spring Mobile 10. Spring with other Web Frameworks 11. ...

    SpringBoot+Mybatis+SpringSecurity+Bootstrap+Layui开发的java web轻量级小巧视频网站系统

    SpringBoot+Mybatis+SpringSecurity+Bootstrap+Layui开发java web轻量级小巧视频网站系统 项目描述 PC端+手机端模式自适应 支持本地资源视频文件上传在线播放,同时支持在线资源链接上传(ed2k、迅雷、等资源)...

    第 5-1 课:使⽤ Spring Boot Security 进⾏安全控制1

    (1)添加依赖: (2)配置文件 (3)创建页面 (4)添加访问入口 (5)添加 Spring Security 依赖 (6)进行分析

    Spring攻略(第二版 中文高清版).part1

    第5章 Spring Security 164 5.1 加强URL访问安全 165 5.1.1 问题 165 5.1.2 解决方案 165 5.1.3 工作原理 166 5.2 登录到Web应用 175 5.2.1 问题 175 5.2.2 解决方案 175 5.2.3 工作原理 175 5.3...

    spring-security-samples

    扫码加微信(微信ID: a_java_boy2 ),备注SpringSecurity,进群讨论。 扫码关注微信公众号【江南一点雨】 ,回复SS获取Spring安全系列完整文章: 本仓库部分Demo有配套视频 视频地址: : 欢迎大家在B站关注我,...

    Spring in Action(第2版)中文版

    第3章高级bean装配 3.1声明父bean和子bean 3.1.1抽象基bean类型 3.1.2抽象共同属性 3.2方法注入 3.2.1基本的方法替换 3.2.2获取器注入 3.3注入非springbean 3.4注册自定义属性编辑器 3.5使用spring的特殊...

    Spring攻略(第二版 中文高清版).part2

    第5章 Spring Security 164 5.1 加强URL访问安全 165 5.1.1 问题 165 5.1.2 解决方案 165 5.1.3 工作原理 166 5.2 登录到Web应用 175 5.2.1 问题 175 5.2.2 解决方案 175 5.2.3 工作原理 175 5.3...

    Spring in Action(第二版 中文高清版).part2

    第三部分 Spring客户端 第13章 处理Web请求 13.1 开始Spring MVC之旅 13.1.1 请求生命中的一天 13.1.2 配置DispatcherServlet 13.1.3 Spring MVC概述 13.2 将请求映射到控制器 13.2.1 使用SimpleUrlHandler ...

    Spring in Action(第二版 中文高清版).part1

    第三部分 Spring客户端 第13章 处理Web请求 13.1 开始Spring MVC之旅 13.1.1 请求生命中的一天 13.1.2 配置DispatcherServlet 13.1.3 Spring MVC概述 13.2 将请求映射到控制器 13.2.1 使用SimpleUrlHandler ...

    JavaEE开发的颠覆者SpringBoot实战[完整版].part3

    第3 章 Spring 高级话题 48 3.1 Spring Aware 48 3.1.1 点睛 48 3.1.2 示例 49 3.2 多线程 51 3.2.1 点睛 51 3.2.2 示例 51 3.3 计划任务 54 3.3.1 点睛 54 3.3.2 示例 54 3.4 条件注解@Conditional 56 3.4.1 点睛 ...

    springCloud

    Spring Cloud包含了多个子项目(针对分布式系统中涉及的多个不同开源产品),比如:Spring Cloud Config、Spring Cloud Netflix、Spring Cloud0 CloudFoundry、Spring Cloud AWS、Spring Cloud Security、Spring ...

Global site tag (gtag.js) - Google Analytics