简介

用于开启Spring方法级安全
在添加了@Configuration注解的类上再添加@EnableGlobalMethodSecurity注解即可

  1. @Configuration
  2. @EnableGlobalMethodSecurity(prePostEnabled=true)
  3. public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  4. }

其中注解@EnableGlobalMethodSecurity有几个方法:

  • prePostEnabled: 确定 前置注解[@PreAuthorize,@PostAuthorize,@PreFilter,@PostFilter,..] 是否启用
  • securedEnabled: 确定安全注解 [@Secured] 是否启用
  • jsr250Enabled: 确定 JSR-250注解 [@RolesAllowed..]是否启用

测试

在同一个应用程序中,可以启用多个类型的注解,
但是只应该设置一个注解对于行为类的接口或者类。
如:

  • 一个程序中可以启用多个类型注解

    1. @Configuration
    2. @EnableWebSecurity
    3. @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true))
    4. public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    5. ...
    6. }
  • 接口或者类只能设置一个

    1. public interface UserService {
    2. List<User> findAllUsers();
    3. @PreAuthorize("hasAnyRole('user')")
    4. void updateUser(User user);
    5. // 下面不能设置两个注解,如果设置两个,只有其中一个生效
    6. @PreAuthorize("hasAnyRole('user')")
    7. @Secured({ "ROLE_user", "ROLE_admin" })
    8. void deleteUser();
    9. }

启用securedEnabled

配置启用之后可以在项目中使用@Secured注解
@Secured:访问目标方法必须具备相应的角色。

  1. @Configuration
  2. @EnableGlobalMethodSecurity(securedEnabled = true))
  3. public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  4. ...
  5. }

使用

在调用的接口或方法使用:

  1. public interface UserService {
  2. List<User> findAllUsers();
  3. @Secured({"ROLE_user"})
  4. void updateUser(User user);
  5. @Secured({"ROLE_admin", "ROLE_user1"})
  6. void deleteUser();
  7. }

功能

@Secured注解是用来定义业务方法的安全配置。
在需要安全[角色/权限等]的方法上指定 @Secured,并且只有那些角色/权限的用户才可以调用该方法。

@Secured缺点(限制)就是不支持Spring EL表达式。不够灵活。并且指定的角色必须以ROLE_开头,不可省略。

而且@Secured注解对于权限只支持单一权限,不支持共同权限
即在上面的例子中,updateUser 方法只能被拥有user权限的用户调用。
deleteUser 方法只能够被拥有admin 或者user1 权限的用户调用。
而如果想要指定”AND”条件,即调用deleteUser方法需同时拥有ADMIN和DBA角色的用户,@Secured便不能实现。
这时就需要使用prePostEnabled提供的注解@PreAuthorize/@PostAuthorize

启用prePostEnabled

可以使用如下四个注解

  • @PostAuthorize:在目标方法执行之后进行权限校验。
  • @PostFilter:在目标方法执行之后对方法的返回结果进行过滤。
  • @PreAuthorize:在目标方法执行之前进行权限校验。
  • @PreFilter:在目标方法执行之前对方法参数进行过滤。

    1. @Configuration
    2. @EnableGlobalMethodSecurity(prePostEnabled = true)
    3. public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    4. ...
    5. }

    使用

    在调用的接口或方法使用:

    1. public interface UserService {
    2. List<User> findAllUsers();
    3. @PostAuthorize ("returnObject.type == authentication.name")
    4. User findById(int id);
    5. @PreAuthorize("hasRole('ADMIN')")
    6. void updateUser(User user);
    7. @PreAuthorize("hasRole('ADMIN') AND hasRole('DBA')")
    8. void deleteUser(int id);
    9. }

功能

该注解更适合方法级的安全,也支持SpringEL 表达式语言,
提供了基于表达式的访问控制。参见常见内置表达式了解支持表达式的完整列表

启用prePostEnabled后,提供有四个注解

1、@PreAuthorize

@PreAuthorize: 进入方法之前验证授权。可以将登录用户的roles参数传到方法中验证。
一些用法:

  1. // 只能user角色可以访问
  2. @PreAuthorize ("hasAnyRole('user')")
  3. // user 角色或者 admin 角色都可访问
  4. @PreAuthorize ("hasAnyRole('user') or hasAnyRole('admin')")
  5. // 同时拥有 user 和 admin 角色才能访问
  6. @PreAuthorize ("hasAnyRole('user') and hasAnyRole('admin')")
  7. // 限制只能查询 id 小于 10 的用户
  8. @PreAuthorize("#id < 10")
  9. User findById(int id);
  10. // 只能查询自己的信息
  11. @PreAuthorize("principal.username.equals(#username)")
  12. User find(String username);
  13. // 限制只能新增用户名称为abc的用户
  14. @PreAuthorize("#user.name.equals('abc')")
  15. void add(User user)


2、@PostAuthorize

@PostAuthorize: 该注解使用不多,在方法执行后再进行权限验证。
适合验证带有返回值的权限。
Spring EL 提供 返回对象能够在表达式语言中获取返回的对象returnObject。
如:

  1. // 查询到用户信息后,再验证用户名是否和登录用户名一致
  2. @PostAuthorize("returnObject.name == authentication.name")
  3. @GetMapping("/get-user")
  4. public User getUser(String name){
  5. return userService.getUser(name);
  6. }
  7. // 验证返回的数是否是偶数
  8. @PostAuthorize("returnObject % 2 == 0")
  9. public Integer test(){
  10. // ...
  11. return id;
  12. }

3、@PreFilter

@PreFilter: 对集合类型的参数执行过滤,移除结果为false的元素

  1. // 指定过滤的参数,过滤偶数
  2. @PreFilter(filterTarget="ids", value="filterObject%2==0")
  3. public void delete(List<Integer> ids, List<String> username)

4、@PostFilter

@PostFilter: 对集合类型的返回值进行过滤,移除结果为false的元素

  1. @PostFilter("filterObject.id%2==0")
  2. public List<User> findAll(){
  3. ...
  4. return userList;
  5. }

总结

对于前面使用@Secured注解的缺点,现在使用@PreAuthorize/@PostAuthorize:即可解决

  1. public interface UserService {
  2. List<User> findAllUsers();
  3. @PostAuthorize ("returnObject.type == authentication.name")
  4. User findById(int id);
  5. @PreAuthorize("hasRole('ADMIN')")
  6. void updateUser(User user);
  7. @PreAuthorize("hasRole('ADMIN') AND hasRole('DBA')")
  8. void deleteUser(int id);
  9. }

启用jsr250Enabled

使用

jsr250Enabled注解比较简单,只有

  • @DenyAll: 拒绝所有访问
  • @PermitAll: 允许所有访问
  • @RolesAllowed({“USER”, “ADMIN”}): 该方法只要具有”USER”, “ADMIN”任意一种权限就可以访问。这里可以省略前缀ROLE_,实际的权限可能是ROLE_ADMIN

总结

一般来说我们只要设置 prePostEnabled=true 就够用了,也就是前四个注解基本上就能满足大部分需求了