Spring Security 保护业务层

保护业务层前端

Spring Security支持添加受权层(或者基于受权的数据处理)到应用中全部Spring管理的bean中。尽管不少的开发人员关注层的安全,其实业务层的安全同等重要,由于恶意的用户可能会穿透web层,可以经过没有UI的前端访问暴露的服务,如使用webservice。java

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

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

  • 事先受权(Pre-authorization)保证在执行一个方法以前须要知足特定的要求——例如,一个用户要拥有特定的GrantedAuthority,如ROLE_ADMIN。不能知足声明的条件将会致使方法调用失败;express

  • 过后受权(Post-authorization)保证在方法返回时,调用的安全实体知足声明的条件。这不多被使用,可是可以在一些复杂交互的业务方法周围提供额外的安全层。        编程

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

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

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

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

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

添加@PreAuthorize方法注解

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

public interface IUserService {  
  @PreAuthorize("hasRole('ROLE_USER')")  
  public void changePassword(String username, String password);  
}

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

让Spring Security可以使用方法注解

         咱们还须要在dogstore-security.xml中作一个一次性的修改,经过这个文件咱们已经进行了Spring Security其余的配置。只须要在<http>声明以前,添加下面的元素便可:

<global-method-security pre-post-annotations="enabled"/>

校验方法安全

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

校验方法安全

         不相信如此简单?那咱们将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。你能够测试修改密码功能对管理员用户依旧是能够访问的。

         咱们只是在接口上添加了简单的声明就可以保证方法的安全,这是否是太使人兴奋了?

         让咱们介绍一下实现方法安全的其它方式,而后进入功能的背后以了解其怎样以及为何可以生效。

几种实现方法安全的方式

         除了@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。取决于你应用对轻便性的需求,你可能会以为牺牲代码的轻便性但减小对特定环境的要求是值得的。

         要实现咱们在第一个例子中的规则,咱们须要做两个修改,首先在

<global-method-security jsr250-annotations="enabled"/>  

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

@RolesAllowed("ROLE_USER")  

public void changePassword(String username, String password); 

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

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

@RolesAllowed({"ROLE_USER","ROLE_ADMIN"})  

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>元素中明确使用另一个属性:

<global-method-security secured-annotations="enabled"/>

由于@Secured与JSR标准的@RolesAllowed注解在功能上一致,因此并无充分的理由在新代码中使用它,可是它可以在Spring的遗留代码中运行。

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

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

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

<global-method-security>  

  <protect-pointcut access="ROLE_ADMIN"   

expression="execution(* com.packtpub.springsecurity.service.I*Service.*(..))"/>  

</global-method-security>  

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

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

<global-method-security>  

  <protect-pointcut access="ROLE_USER"   

expression="execution(* com.packtpub.springsecurity.dao.IProductDao.getCategories(..)) &&  args()"/>  

  <protect-pointcut access="ROLE_ADMIN" expression="execution(* com.packtpub.springsecurity.service.I*Service.*(..))"/>  

</global-method-security>  

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

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

         使用AOP来进行编程即使是经验丰富的开发人员可能也会感到迷惑。

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

相关文章
相关标签/搜索