乐趣区

使用Spring安全表达式控制系统功能访问权限

一、SPEL 表达式权限控制

spring security 3.0 开始已经可以使用 spring Expression 表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。Spring Security 可用表达式对象的基类是 SecurityExpressionRoot。

表达式函数 描述
hasRole([role]) 用户拥有指定的角色时返回 true(Spring security默认会带有 ROLE_ 前缀), 去除前缀参考 Remove the ROLE_
hasAnyRole([role1,role2]) 用户拥有任意一个指定的角色时返回 true
hasAuthority([authority]) 拥有某资源的访问权限时返回 true
hasAnyAuthority([auth1,auth2]) 拥有某些资源其中部分资源的访问权限时返回 true
permitAll 永远返回 true
denyAll 永远返回 false
anonymous 当前用户是 anonymous 时返回 true
rememberMe 当前用户是 rememberMe 用户返回 true
authentication 当前登录用户的 authentication 对象
fullAuthenticated 当前用户既不是 anonymous 也不是 rememberMe 用户时返回 true
hasIpAddress('192.168.1.0/24')) 请求发送的 IP 匹配时返回 true

部分朋友可能会对 Authority 和 Role 有些混淆。Authority 作为资源访问权限可大可小,可以是某按钮的访问权限(如资源 ID:biz1),也可以是某类用户角色的访问权限(如资源 ID:ADMIN)。当 Authority 作为角色资源权限时,hasAuthority(’ROLE_ADMIN’)与 hasRole(’ADMIN’)是一样的效果。

二、SPEL 在全局配置中的使用

我们可以通过继承 WebSecurityConfigurerAdapter,实现相关的配置方法,进行全局的安全配置(之前的章节已经讲过)。下面就为大家介绍一些如何在全局配置中使用 SPEL 表达式。

2.1.URL 安全表达式

config.antMatchers("/system/*").access("hasAuthority('ADMIN') or hasAuthority('USER')")
      .anyRequest().authenticated();

这里我们定义了应用 /person/*URL 的范围,只有拥有ADMIN 或者 USER 权限的用户才能访问这些 person 资源。

2.2. 安全表达式中引用 bean

这种方式,比较适合有复杂权限验证逻辑的情况,当 Spring Security 提供的默认表达式方法无法满足我们的需求的时候。首先我们定义一个权限验证的 RbacService。

@Component("rbacService")
@Slf4j
public class RbacService {
    // 返回 true 表示验证通过
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        // 验证逻辑代码
        return true;
    }
    public boolean checkUserId(Authentication authentication, int id) {
        // 验证逻辑代码
        return true;
    }
}

对于 ”/person/{id}” 对应的资源的访问,调用 rbacService 的 bean 的方法 checkUserId 进行权限验证,传递参数为 authentication 对象和 person 的 id。该 id 为 PathVariable,以 #开头表示。

config.antMatchers("/person/{id}").access("@rbacService.checkUserId(authentication,#id)")
      .anyRequest().access("@rbacService.hasPermission(request,authentication)");

三、Method 表达式安全控制

如果我们想实现方法级别的安全配置,Spring Security提供了四种注解,分别是@PreAuthorize , @PreFilter , @PostAuthorize 和 @PostFilter

3.1. 开启方法级别注解的配置

在 Spring 安全配置代码中,加上 EnableGlobalMethodSecurity 注解,开启方法级别安全配置功能。

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

3.2 使用 PreAuthorize 注解

@PreAuthorize 注解适合进入方法前的权限验证。只有拥有 ADMIN 角色才能访问 findAll 方法。

@PreAuthorize("hasRole('ADMIN')")
List<Person> findAll();

3.3 使用 PostAuthorize 注解

@PostAuthorize 在方法执行后再进行权限验证, 适合根据返回值结果进行权限验证。Spring EL 提供返回对象能够在表达式语言中获取返回的对象returnObject。下文代码只有返回值的 name 等于 authentication 对象的 name 才能正确返回,否则抛出异常。

@PostAuthorize("returnObject.name == authentication.name")
Person findOne(Integer id);

3.4 使用 PreFilter 注解

PreFilter 针对参数进行过滤, 下文代码表示针对 ids 参数进行过滤,只有 id 为偶数才能访问 delete 方法。

// 当有多个对象是使用 filterTarget 进行标注
@PreFilter(filterTarget="ids", value="filterObject%2==0")
public void delete(List<Integer> ids, List<String> usernames) {

3.5 使用 PostFilter 注解

PostFilter 针对返回结果进行过滤,特别适用于集合类返回值,过滤集合中不符合表达式的对象。

@PostFilter("filterObject.name == authentication.name")
List<Person> findAll();

期待您的关注

  • 博主最近新写了一本书:《手摸手教您学习 SpringBoot 系列 -16 章 97 节》
  • 本文转载注明出处(必须带连接,不能只转文字):字母哥博客。
退出移动版