《Spring Security 3》 精确的访问控制

添加@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>声明之前,添加下面的元素即可:

 

java代码:
  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文件中:

 

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

 

 

java代码:
  1. <global-method-security secured-annotations="enabled"/>    

 

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

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

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

 

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

 

 

java代码:
  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中一个方法的例子:

 

java代码:
  1. <global-method-security>    
  2.   <protect-pointcut access="ROLE_USER"     
  3.           expression="execution(* com.packtpub.springsecurity.dao.IProductDao.getCategories(..)) &&  args()"/>    
  4.   <protect-pointcut access="ROLE_ADMIN" expression="execution(* com.packtpub.springsecurity.service.I*Service.*(..))"/>    
  5. </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的使用也提供了相当丰富的环境来开发基本的安全声明。


原文 http://sishuok.com/forum/blogCategory/showByCategory.html?categories_id=77&user_id=2

发布了38 篇原创文章 · 获赞 1 · 访问量 27万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章