Spring学习笔记之保护方法应用

在本章中我们将会看到如何使用Spring Security保护bean方法。

1.使用注解保护方法

在Spring Security中实现方法级安全性的最常见办法是使用特定的注解,将这些注解应用到需要保护的方法上。这样有几个好处,最重要的是当我们在编辑器中查看给定的方法时,能够很清楚地看到它的安全规则。
Spring Security提供了三种不同的安全注解:

  • Spring Security自带的@Security注解
  • JSR-250的@RolesAllowed注解
  • 表达式驱动的注解,包括@PreAuthorize,@PostAuthorize,@PreFilter,@PostFilter。

1.1使用@Secured注解限制方法调用

在Spring中,如果要启用基于注解的方法安全性,关键之处在于要在配置类上使用@EnableGlobalMethodSecurity:

@Configuration
@EnableGlobalMethodSecurity(securedEnabled=true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration{

}

GlobalMethodSecurityConfiguration类能够为方法级别的安全性提供更精细的配置。
如果securedEnabled属性的值为true的话,将会创建一个切点,这样的话Spring Security切面就会包装带有@Security注解的方法。(所以最好把要控制权限的方法放在service层)。

示例:

@Service
public class SecurityService {
    @Secured("ROLE_ADMIN")
    public void test1(){
        System.out.println("拥有ADMIN权限");
    }

    @Secured({"ROLE_ADMIN","ROLE_USER"})
    public void test2(){
        System.out.println("拥有ADMIN或USER权限");
    }
}

@Secured注解的不足之处在于它是spring特定的注解。如果更倾向于使用Java标准定义的注解,那么你应该考虑使用@RolesAllowed注解

1.2在Spring Security中使用JSR-250的@RolesAllowed注解

@RolesAllowed是JSR-250定义的Java标准注解。如果选择@RolesAllowed的话,需要将@EnableGlobalMethodSecurity的jsr250Enabled属性设置为true,以开启此功能:

@Configuration
@EnableGlobalMethodSecurity(securedEnabled=true,jsr250Enabled=true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration{

}

使用示例:

@Service
public class SecurityService {
    @RolesAllowed("ROLE_ADMIN")
    public void test1(){
        System.out.println("拥有ADMIN权限");
    }

    @RolesAllowed({"ROLE_ADMIN","ROLE_USER"})
    public void test2(){
        System.out.println("拥有ADMIN或USER权限");
    }
}

2.使用表达式实现方法级别的安全性

Spring Security 3.0提供了4个新的注解,可以使用SpEL表达式来保护方法调用

注解描述
@PreAuthorize在方法调用之前,基于表达式的计算结果来限制对方法的访问
@PostAuthorize允许方法调用,但是如果表达式计算结果为false,将抛出一个安全性异常
@PostFilter允许方法调用,但必须按照表达式来过滤方法的结果
@PreFilter允许方法调用,但必须在进入方法之前过滤输入值

首先,我们需要将@EnableGlobalMethodSecurity的prePostEnabled属性值设为true,从而开启它们:

@Configuration
@EnableGlobalMethodSecurity(securedEnabled=true,jsr250Enabled=true,prePostEnabled=true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration{

}

2.1表述方法访问规则

@PreAuthorize和@PostAuthorize能够基于表达式的计算结果来限制方法的访问。区别在于表达式执行的时机。@PreAuthorize的表达式会在方法调用之前执行,如果表达式的计算结果不为true的话,将会阻止方法执行。与之相反,@PostAuthorize的表达式知道方法返回才会执行,然后根据结果决定是否抛出安全性异常,如果为false,会抛出一个AccessDeniedException异常,而调用者也得不到返回的值。

@Service
public class SecurityService {
    @PreAuthorize("hasRole('ROLE_ADMIN') and #num > 5")
    public void test1(int num){
        System.out.println("拥有ADMIN权限并且输入的数字大于5");
    }

    @PostAuthorize("returnObject == 'abc'")
    public String test2(){
        System.out.println("执行方法并返回一个字符串对象");
        return "abcd";
    }
}

为了便利地访问受保护方法的返回对象,Spring Security在SpEL中提供了名为returnObject的变量。

2.2 过滤方法的输入和输出

@PostFilter和@PreFilter都使用一个SpEL作为值参数,但是这个表达式不是用来限制方法访问的,@PostFilter会使用这个表达式计算该方法所返回集合的每个成员,将计算结果为false的成员从结果集中除掉,返回结果集。而@PreFilter过滤的是要进入方法中的集合,同样会对每一条数据进行检查,只有满足表达式(即表达式返回true)的结果才能保留在集中,最终传到方法里面。

@Service
public class SecurityService {
    /**
     * 需要拥有ADMIN或USER权限才能访问,
     * ADMIN缺陷的话返回所有数据,
     * USER权限的话只返回和登录用户相同用户名的数据
     * @return
     */
    @PreAuthorize("hasAnyRole({'ROLE_ADMIN','ROLE_USER'})")
    @PostFilter("hasRole('ROLE_ADMIN') || "
            + "filterObject.username == principal.username")
    public List<User> test1(){
        User u1 = new User("xuexiaoqiang");
        User u2 = new User("admin");
        User u3 = new User("xueqiang");
        List<User> list = new ArrayList<User>();
        list.add(u1);
        list.add(u2);
        list.add(u3);
        return list;
    }

    /**
     * 需要拥有ADMIN或USER权限才能访问,
     * 拥有ADMIN权限的用户会将数据全部传入方法中
     * 拥有USER权限的用户只会将相同用户名的数据传进去
     * @param users
     */
    @PreAuthorize("hasAnyRole({'ROLE_ADMIN','ROLE_USER'})")
    @PreFilter("hasRole('ROLE_ADMIN') || "
            + "filterObject.username == principal.username")
    public void test2(List<User> users){
        for(User u : users){
            System.out.println(u.getUsername());
        }
    }
}

filterObject对象引用的是传入或传出的List中的某一个元素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值