循序渐进学spring security 第十三篇 四种权限控制是什么?项目中如何使用案例

回顾

前面我们通过《循序渐进学spring security 第七篇,如何基于用户表和权限表配置权限?越学越简单了》介绍了如何通过动态给用户授权和控制URL权限,后面又通过《循序渐进学spring security 第十一篇 如何动态权限控制URL?如何动态给用户添加权限?》介绍了如何动态分配URL权限和用户权限,今天,我们继续介绍权限的四种模式

  • 表达式控制 URL 路径权限
  • 表达式控制方法权限
  • 使用过滤注解
  • 动态权限

四种模式

表达式控制 URL 路径权限

其实就是通过表达式控制 URL 路径权限,这种方式在之前的文章中实际上和大家讲过,这里我们再来稍微复习一下。

Spring Security 支持在 URL 和方法权限控制时使用 SpEL 表达式,如果表达式返回值为 true 则表示需要对应的权限,否则表示不需要对应的权限。提供表达式的类是 SecurityExpressionRoot:

在这里插入图片描述
可以看到,SecurityExpressionRoot 有两个实现类,表示在应对 URL 权限控制和应对方法权限控制时,分别对 SpEL 所做的拓展,例如在基于 URL 路径做权限控制时,增加了 hasIpAddress 选项。

我们来看下 SecurityExpressionRoot 类中定义的最基本的 SpEL 有哪些:
在这里插入图片描述
可以看到,这些都是该类对应的表达式,这些表达式我列出来了表格,说明其功能

表达式备注
hasRole具备指定角色可访问资源权限
hasAnyRole具备多个角色中的任意一个即可访问资源
hasAuthority类似于 hasRole
hasAnyAuthority类似于 hasAnyRole
permitAll统统允许访问
denyAll统统拒绝访问
isAnonymous判断是否匿名用户
isAuthenticated判断是否认证成功
isRememberMe判断是否通过记住我登录的
isFullyAuthenticated判断是否用户名/密码登录的
principle当前用户
authentication从 SecurityContext 中提取出来的用户对象

这里列举的是最基本的比较常用的方法

如果是通过 URL 进行权限控制,那么我们只需要按照如下方式配置即可:

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/**").hasRole("admin")
                .antMatchers("/user/**").hasRole("user")
                .anyRequest().authenticated()
             ;
    }

这里表示访问

  • /admin/** 格式的路径需要 admin 角色
  • 访问 /user/** 格式的路径需要 user 角色

这就是静态配置,需要事先确定好哪些URL拥有什么权限才能访问时,可以通过这种方式配置,但是通过这种方式配置,有个缺点,就是每次新增接口权限时,都得到配置文件中去配置权限,即需要修改原来的代码,容易引起bug,因此,在开发中,一般不会通过这种方式配置

表达式控制方法权限

当然,我们也可以通过在方法上添加注解来控制权限。需要我们首先开启注解@EnableGlobalMethodSecurity的使用,在 Spring Security 配置类上添加如下内容:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    ...
    ...
}

这个配置开启了三个注解,分别是:

注解备注
@PreAuthorize方法执行前进行权限检查
@PostAuthorize方法执行后进行权限检查
@Secured类似于 @PreAuthorize

这三个结合 SpEL 之后,用法非常灵活,这里和大家稍微分享几个 Demo

  /**
     *  @PreAuthorize("principal.username.equals('mike')") 注解的约束是,只有当前登录用户名为 mike 的用户才可以访问该方法。
     * @return
     */
    @PreAuthorize("principal.username.equals('mike')")
    @RequestMapping("/hello")
    public String hello(){
        return "一望二三里----某某诗人,hello user: "+getLoginUser();
    }

    /**
     *  @PreAuthorize("hasRole('admin')") 表示访问该方法的用户必须具备 admin 角色。
     * @return
     */
    @RequestMapping("/admin/index")
    @PreAuthorize("hasRole('admin')")
    public String adminIndex(){
        return "落霞与孤鹜齐飞,秋水共长天一色----某某诗人,hello user: "+getLoginUser();
    }

    /**
     * @Secured({"ROLE_user"})表示方法该方法的用户必须具备 user 角色,但是注意 user 角色需要加上 ROLE_ 前缀。
     * @return
     */
    @RequestMapping("/user/index")
    @Secured({"ROLE_user"})
    public String userIndex(){
        return "采菊东篱下悠然见南山----陶渊明,hello user: "+getLoginUser();
    }

    /**
     * 访问该接口的 score 参数必须大于 80,否则请求不予通过。
     * @return
     */
    @RequestMapping("/score")
    @PreAuthorize("#score>80")
    public String getScore(int score){
        return "当前登录用户"+getLoginUser()+"查询成绩:"+score;
    }
  • 第一个 /hello 接口,注解的约束是,只有当前登录用户名为 mike 的用户才可以访问该方法。
  • 第二个 /admin/index 接口,表示访问该方法的用户必须具备 admin 角色。
  • 第三个 /user/index 接口,表示方法该方法的用户必须具备 user 角色,但是注意 user 角色需要加上 ROLE_ 前缀。
  • 第四个 /score 接口,表示访问该方法的 score 参数必须大于 80,否则请求不予通过。

这里的表达式还是非常丰富,如果想引用方法的参数,前面加上一个 # 即可,既可以引用基本类型的参数,也可以引用对象参数。
缺省对象除了 principal ,还有 authentication

其实,这些注解表达式,不仅可以用在controller接口上,也可以用在service,或者其他spring管理的bean方法上。
很显然,利用表达式控制方法权限 才是适合我们开发中经常会用到的,为什么?比如我现在需要新增一个controller接口,需要对某些方法进行URL权限控制,我就不需要去修改配置,增加一个URL和指定权限了,只需要在我这个controller的方法里面,增加个注解,如 @PreAuthorize(“hasRole(‘admin’)”) 其中admin就是对应URL应该要控制的权限,这样就完成了。这样的好处是,不需要去修改已有的代码,从而更好的避免bug的发生

使用过滤注解

Spring Security 中还有两个过滤函数 @PreFilter 和 @PostFilter,可以根据给出的条件,自动移除集合中的元素。

    @RequestMapping("/getAllStudentScore")
    @PostFilter("filterObject>5")
    public List<Integer> getAllStudentScore() {
        List<Integer> users = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            users.add(i);
        }
        return users;
    }

    @RequestMapping("/getAllAge")
    // @PreFilter("filterObject%2==0")
    @PreFilter(filterTarget = "ages",value = "filterObject%2==0")
    public List<Integer> getAllAge(@RequestBody List<Integer> ages) {
        System.out.println("ages = " + ages);
        return ages;
    }
  • 在 getAllStudentScore 接口中,对集合进行过滤,只返回分数大于5的元素,filterObject 表示要过滤的元素对象。
  • 在 getAllAge 方法中,如果只有一个集合参数,可以不用指定filterTarget 指定过滤对象,如果有多个参数,就需要指定

当然,这些注解不仅可以用在接口这里,也可以用在其他spring管理的bean上定义的,过滤注解非常灵活了,开发起来就很顺手,对于在原有接口做拓展时,用起来就是屡试不爽

以前,我要在某个方法返回数据之前,对数据进行过滤之后,将满足条件的数据返回,不满足的过滤掉,怎么做?
因为我不想去修改原有代码,因为代码不一定是我写的,逻辑非常复杂,去改别人的代码甚至自己的代码都是容易引起bug的,然后我就会写一个AOP去拓展,将方法返回数据后,在遍历去过滤满足条件的数据,然后再返回,每次都要新建AOP去处理,也是蛮痛苦的,因为也需要写一堆的过滤逻辑

那现在怎么做?
可以去改原有代码,但是这次怎么改呢?只需轻轻的在方法上面加个注解 @PostFilter,然后将过滤条件写上,就可以了,是不是爽多了?
可能有人会说,这不是要去改原有代码吗?这也没错,但是仔细看,你会发现,我只是加了个注解,没有修改原有的业务逻辑,是不会引起其他bug的,这个代价还是非常小的

动态权限

其实前面我们通过《循序渐进学spring security 第十一篇 如何动态权限控制URL?如何动态给用户添加权限?》已经介绍过动态权限了,如果没看过我之前的文章的,可以先去看看

好了,通过这篇文章,对于spring security的权限管理是不是更加了解了?如果这篇文章的知识领悟到了,在开发过程中,将会帮助到你很多关于权限控制方面的,还可以让你的开发效率上一高层

本文涉及到的代码,我是在之前《循序渐进学spring security 第十一篇 如何动态权限控制URL?如何动态给用户添加权限?》项目的基础上写的,我后面会上传代码到git仓库,大家可以下载下来体验一下,下载地址可以去之前文章下载

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值