第 19 章 保护方法调用

这里有三种方式可以选择:

19.1. 控制全局范围的方法权限

使用global-method-security和protect-point标签来管理全局范围的方法权限。
为了在spring中使用AOP,我们要为项目添加几个依赖库。
<dependency>
  <groupId>cglib</groupId>
  <artifactId>cglib-nodep</artifactId>
  <version>2.1_3</version>
</dependency>
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjrt</artifactId>
  <version>1.6.4</version>
</dependency>
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.6.4</version>
</dependency>
        
首先来看看我们将要保护的java类。
package com.family168.springsecuritybook.ch12;
public class MessageServiceImpl implements MessageService {
    public String adminMessage() {
        return "admin message";
    }
    public String adminDate() {
        return "admin " + System.currentTimeMillis();
    }
    public String userMessage() {
        return "user message";
    }
    public String userDate() {
        return "user " + System.currentTimeMillis();
    }
}
        
这里使用的是spring-2.0中的aop语法,对MessageService中所有以admin开头的方法进行权限控制,限制这些方法只能由ROLE_ADMIN调用。
<global-method-security>
    <protect-pointcut
        expression="execution(* com.family168.springsecuritybook.ch12.MesageServiceImpl.admin*(..))"
        access="ROLE_ADMIN"/>
</global-method-security>
        
现在只有拥有ROLE_ADMIN权限的用户才能调用MessageService中以admin开头的方法了,当我们以user/user登陆系统时,尝试调用MessageService类的adminMessage()会跑出一个“访问被拒绝”的异常。

19.2. 控制某个bean内的方法权限

在bean中嵌入intercept-methods和protect标签。
这需要改造配置文件。
<beans:bean id="messageService" class="com.family168.springsecuritybook.ch12.MessageServiceImpl">
    <intercept-methods>
        <protect access="ROLE_ADMIN" method="userMessage"/>
    </intercept-methods>
</beans:bean>
        
现在messageService中的userMessage()方法只允许拥有ROLE_ADMIN权限的用户才能调用了。

使用intercept-methods面临着几个问题

首先,intercept-methods只能使用jdk14的方式拦截实现了接口的类,而不能用cglib直接拦截无接口的类。
其次,intercept-methods和global-method-security一起使用,同时使用时,global-method-security一切正常,intercept-methods则会完全不起作用。

19.3. 使用annotation控制方法权限

借助jdk5以后支持的annotation,我们直接在代码中设置某一方法的调用权限。
现在有两种选择,使用Spring Security提供的Secured注解,或者使用jsr250规范中定义的注解。

19.3.1. 使用Secured

首先修改global-method-security中的配置,添加支持annotation的参数。
<global-method-security secured-annotations="enabled"/>
            
然后添加依赖包。
<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-core-tiger</artifactId>
  <version>2.0.4</version>
</dependency>
            
现在我们随便在java代码中添加注解了。
package com.family168.springsecuritybook.ch12;
import org.springframework.security.annotation.Secured;
public class MessageServiceImpl implements MessageService {
    @Secured({"ROLE_ADMIN", "ROLE_USER"})
    public String userMessage() {
        return "user message";
    }
}
            
在Secured中设置了ROLE_ADMIN和ROLE_USER两个权限,只要当前用户拥有其中任意一个权限都可以调用这个方法。

19.3.2. 使用jsr250

首先还是要修改配置文件。
<global-method-security secured-annotations="enabled"
                           jsr250-annotations="enabled"/>
            
然后添加依赖包。
<dependency>
  <groupId>javax.annotation</groupId>
  <artifactId>jsr250-api</artifactId>
  <version>1.0</version>
</dependency>
            
现在可以在代码中使用jsr250中的注解了。
package com.family168.springsecuritybook.ch12;
import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
public class MessageServiceImpl implements MessageService {
    @RolesAllowed({"ROLE_ADMIN", "ROLE_USER"})
    public String userMessage() {
        return "user message";
    }
    @DenyAll
    public String userMessage2() {
        return "user message";
    }
    @PermitAll
    public String userMessage2() {
        return "user message";
    }
}
            
1
RolesAllowed与前面的Secured功能相同,用户只要满足其中定义的权限之一就可以调用方法。
2
DenyAll拒绝所有的用户调用方法。
3
PermitAll允许所有的用户调用方法。
从实际使用上来讲,jsr250里多出来的DenyAll和PermitAll纯属浪费,谁会定义谁也不能调用的方法呢?实际上,要是annotation支持布尔操作就好了,比如逻辑并,逻辑或,逻辑否之类的。
还有jsr250中未被支持的RunAs注解,如果能利用起来估计更有趣。
实例在ch201。