首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >重新梳理了一下Spring Security的注解访问权限控制

重新梳理了一下Spring Security的注解访问权限控制

作者头像
码农小胖哥
发布2022-05-22 09:44:58
发布2022-05-22 09:44:58
2.1K0
举报

Spring Security提供基于注解的访问控制。

开启方法注解访问控制

Spring Security默认是关闭方法注解的,开启它只需要通过引入@EnableGlobalMethodSecurity注解即可:

代码语言:javascript
复制
/**
 * 开启方法安全注解
 *
 * @author  felord.cn
 */
@EnableGlobalMethodSecurity(prePostEnabled = true,
        securedEnabled = true,
        jsr250Enabled = true)
public class MethodSecurityConfig {
}

@EnableGlobalMethodSecurity 提供了 prePostEnabledsecuredEnabledjsr250Enabled 三种方式,可以根据需要选择使用这三种的一种或者其中几种。

@EnableGlobalMethodSecurity

@EnableGlobalMethodSecurity的思维导图可以帮助你梳理相关的逻辑。

黄色区域是注解访问控制的基本知识点,需要重点掌握,我们先来看看基本的用法。

@PreAuthorize和@PostAuthorize

prePostEnabled等于true时启用。

在标记的方法调用之前或者之后,通过SpEL表达式来计算是否可以调用方法或者调用后是否可以返回结果。总结了一些常用的表达式样例:

SpEL表达式

说明

principal.username ne 'felord'

当前principal的username不能是felord

authentication.authorities.contains('ROLE_ADMIN')

当前Authentication的authorities包含ROLE_ADMIN

hasRole('ADMIN')

当前用户必须有角色ROLE_ADMIN,等同于上面

hasAnyRole('ADMIN','USER')

当前用户角色必须有ROLE_ADMIN或者ROLE_USER

hasAuthority('ROLE_ADMIN')

同hasRole

hasAnyAuthority('ROLE_ADMIN','ROLE_USER')

同hasAnyRole

#requestParam eq 'felord'

当前请求参数requestParam(可以是对象,这里是字符串示例)值等于felord

❝其它表达式可参考SpEL官方文档。

如果用户felord访问下面这个接口,方法不但不执行还会403

代码语言:javascript
复制
    /**
     *  当前用户名不是felord 才能访问 否则403
     * @param req req
     * @return map
     */
    @GetMapping("/prepost")
    @PreAuthorize("authentication.principal.username ne 'felord'")
    public  Map<String, String> prepost(String req){
        Map<String, String> map = Collections.singletonMap("req", req);
        System.out.println("map = " + map);
        return map;
    }

如果方法上的注解改为@PostAuthorize("authentication.principal.username ne 'felord'"),控制台会打印

从日志上可以明显看出方法确实执行了,但是还是给了403

@PreFilter和@PostFilter

prePostEnabled等于true时启用。

这两个注解可以看做@PreAuthorize@PostAuthorize的加强版。它们除了能实现@PreAuthorize@PostAuthorize外还具有过滤请求响应数据的能力。限定处理的数据类型有Collection数组MapStream。举个例子:

代码语言:javascript
复制
    // ids =  ["Felordcn","felord","jetty"]
    @PostMapping("/prefilter")
    @PreFilter(value = "hasRole('ADMIN') and filterObject.startsWith('f')",
               filterTarget = "ids")
    public Collection<String> preFilter(@RequestBody Collection<String> ids){
         // ids = ["felord"]
        System.out.println("ids = " + ids);
        return ids;
    }

上面的接口方法有两层含义:

  • 当前用户必须持有角色ROLE_ADMIN,否则方法不执行。这一条件不存在的话方法一定会执行。
  • 如果方法执行的话,入参ids集合中不包含f开头的元素都会被移除,返回值为felord

❝过滤元素的底层是java.util.Collection#remove(Object);另外多个入参需要使用filterTarget指定参数名称。

@PostFilter也很好理解,拿下面的方法来说:

代码语言:javascript
复制
    @GetMapping("/postfilter")
    @PostFilter("hasRole('ADMIN') and filterObject.startsWith('f')")
    public Collection<String> postfilter(){
        List<String> list = new ArrayList<>();
        list.add("Felordcn");
        list.add("felord");
        list.add("jetty");
        // list = ["felord"]
        System.out.println("list = " + list);
        return list;
    }

无论是否满足@PostFilter表达式的条件,都会打印list = ["felord"],条件成立返回list,不成立则返回403

❝这两个注解用来控制请求和相应中集合、流中的数据。

@Secured

securedEnabled等于true时启用。

该注解功能要简单得多,默认情况下只能基于角色(默认需要带前缀 ROLE_)集合来进行访问控制决策。该注解的机制是只要其声明的角色集合(value)中包含当前用户持有的任一角色就可以访问,也就是用户的角色集合和 @Secured 注解的角色集合要存在非空的交集。不支持使用 SpEL 表达式进行决策。过于简单不再演示。

@Secured等同于hasAnyAuthority

JSR-250

jsr250Enabled等于true时启用。

启用 JSR-250 安全控制注解,这属于 JavaEE 的安全规范(现为 jakarta 项目)。Spring Security中使用了JavaEE 安全注解中的以下三个:

  • @DenyAll 拒绝所有的访问
  • @PermitAll 同意所有的访问
  • @RolesAllowed 用法和上面的 @Secured 一样。
注解控制的优劣

使用注解的好处就是绑定了接口方法,控制粒度非常细,甚至能做一些数据层面的访问控制。劣势在于它是静态织入Java代码中的,灵活性难以把握。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-04-15,如有侵权请联系 cloudcommunity@tencent.com 删除
目录
  • 开启方法注解访问控制
  • @EnableGlobalMethodSecurity
    • @PreAuthorize和@PostAuthorize
    • @PreFilter和@PostFilter
    • @Secured
    • JSR-250
  • 注解控制的优劣
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档