Spring Security 中自定义权限表达式

这篇具有很好参考价值的文章主要介绍了Spring Security 中自定义权限表达式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

这是我在这个网站整理的笔记,有错误的地方请指出,关注我,接下来还会持续更新。 作者:神的孩子都在歌唱

一. SpEL中使用自定义Bean

通过编程授权方法

首先,声明一个 Bean,如下所示:

@Service("authz")
public class PermissionService {
      /**
     * 验证用户是否具备某权限
     *
     * @param permission 权限字符串
     * @return 用户是否具备某权限
     */
    public boolean hasPerm(String permission) {
        // 逻辑处理
    }
    
}

然后,在注解中以如下方式引用该 Bean:

@Controller
public class MyController {
    @PreAuthorize("@authz.hasPerm('com:user:ip')")
    @GetMapping("/endpoint")
    public String endpoint() {
        // ...
    }
}

Spring Security 将在每次方法调用时调用该Bean上的给定方法。

这样做的好处是所有的授权逻辑都在一个单独的类中,可以独立进行单元测试并验证其正确性。

二. 通过类继承自定义权限表达式

  1. 第一种的缺点:

    (1) 使用第一种方式idea会有告警,使得项目很难看

    Spring Security 中自定义权限表达式,# springboot,# spring Security,spring,java,后端

    (2) 这种自定义方式太自由了,没有在 Spring Security 架构内完成这件事。所以,我们要在不使用第三方对象的情况下,来自定义一个权限判断的表达式。

我们在 @PreAuthorize 注解中使用的不用加对象名就能调用的授权字段和方法,如 hasAuthority、hasPermission、hasRole、hasAnyRole 等, Spring Security 将所有授权字段和方法封装在一组根(root)对象中。最通用的根对象称为 SecurityExpressionRoot,它构成了 MethodSecurityExpressionRoot 的基础。当准备评估授权表达式时,Spring Security 会将该根对象提供给 MethodSecurityEvaluationContext

2.1 自定义 ExpressionRoot

首先我们自定义一个类继承自 SecurityExpressionRoot 并实现 MethodSecurityExpressionOperations 接口(本来直接继承自 MethodSecurityExpressionRoot 即可,但是因为这个类不是 public 的,没法继承,所以我们就实现 MethodSecurityExpressionOperations 接口即可):

/**
 * 自定义权限实现
 *
 * @author chenyunzhi
 */
public class PermissionSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {

    private Object filterObject;

    private Object returnObject;

    private Object target;


    /**
     * 所有权限标识
     */
    private static final String ALL_PERMISSION = "*:*:*";

    private static final String PERMISSION_DELIMETER = ",";

    /**
     * Creates a new instance
     *
     * @param authentication the {@link Authentication} to use. Cannot be null.
     */
    public PermissionSecurityExpressionRoot(Authentication authentication) {
        super(authentication);
    }

    /**
     * 验证用户是否具备某权限
     *
     * @param permission 权限字符串
     * @return 用户是否具备某权限
     */
    public boolean hasPerm(String permission) {
        if (StringUtils.isEmpty(permission)) {
            return false;
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) {
            return false;
        }
        return hasPermissions(loginUser.getPermissions(), permission);
    }

    /**
     * 验证用户是否具有以下任意一个权限
     *
     * @param permissions 以 PERMISSION_NAMES_DELIMETER 为分隔符的权限列表
     * @return 用户是否具有以下任意一个权限
     */
    public boolean hasAnyPerm(String permissions) {
        if (StringUtils.isEmpty(permissions)) {
            return false;
        }
//        LoginUser loginUser = SecurityUtils.getLoginUser();
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) {
            return false;
        }
        Set<String> authorities = loginUser.getPermissions();
        for (String permission : permissions.split(PERMISSION_DELIMETER))
        {
            if (permission != null && hasPermissions(authorities, permission))
            {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断是否包含权限
     *
     * @param permissions 权限列表
     * @param permission  权限字符串
     * @return 用户是否具备某权限
     */
    private boolean hasPermissions(Set<String> permissions, String permission) {
        return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
    }

    @Override
    public void setFilterObject(Object filterObject) {
        this.filterObject = filterObject;
    }

    @Override
    public Object getFilterObject() {
        return this.filterObject;
    }

    @Override
    public void setReturnObject(Object returnObject) {
        this.returnObject = returnObject;
    }

    @Override
    public Object getReturnObject() {
        return this.returnObject;
    }

    @Override
    public Object getThis() {
        return this.target;
    }
}

Spring Security 中,MethodSecurityExpressionRoot 的配置是通过 DefaultMethodSecurityExpressionHandler 来完成的,现在我们自定义了 PermissionSecurityExpressionRoot, 所以,再来一个PermissionSecurityExpressionHandler类继承DefaultMethodSecurityExpressionHandler,如下:

/**
 * @author chenyunzhi
 * @description: 定义handler配置 PermissionSecurityExpressionRoot
 */
@Component
public class PermissionSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler {
    @Override
    protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) {
        PermissionSecurityExpressionRoot root = new PermissionSecurityExpressionRoot(authentication);
        root.setTrustResolver(getTrustResolver());
        root.setPermissionEvaluator(getPermissionEvaluator());
        root.setRoleHierarchy(getRoleHierarchy());
        return root;
    }
}

然后就可以通过以下注解使用了

@PreAuthorize("hasPerm('com:user:add')")

三. 参考文章

如何在 Spring Security 中自定义权限表达式

security中文文档

作者:神的孩子都在歌唱
本人博客:https://blog.csdn.net/weixin_46654114
转载说明:务必注明来源,附带本人博客连接。文章来源地址https://www.toymoban.com/news/detail-739513.html

到了这里,关于Spring Security 中自定义权限表达式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【SpringBoot应用篇】【AOP+注解】SpringBoot+SpEL表达式基于注解实现权限控制

    Spring 表达式语言 SpEL 是一种非常强大的表达式语言,它支持在运行时查询和操作对象图。 它提供了许多高级功能,例如方法调用和基本的字符串模板功能。 表达式语言给静态Java语言增加了动态功能。 Spring 表达式语言最初是为 Spring 社区创建的,它拥有一种受良好支持的表

    2024年02月20日
    浏览(45)
  • SpringBoot自定义cron表达式注册定时任务

    1、使用Spring自带的TaskScheduler注册任务 2、注册后返回:ScheduledFuture,用于取消定时任务 3、注册任务后不会马上取消任务,所以将任务缓存。在需要取消任务的时候调用取消接口取消 4、cron表达式可以由前端或者后端生成。实现中会校验cron表达式 1、配置任务调度器 作用:设

    2023年04月21日
    浏览(38)
  • Spring AOP切入点表达式

    先来认识两个概念吧(其实Spring AOP实现功能增强的方式就是代理模式) 目标对象(Target):原始功能去掉共性功能对应的类产生的对象,这种对象是无法直接完成最终工作的 代理(Proxy):目标对象无法直接完成工作,需要对其进行功能回填,通过原始对象的代理对象实现 回归主

    2023年04月24日
    浏览(45)
  • Spring表达式语言(SPEL)学习(03)

    在表达式中直接写name和getName(),这时候Expression是无法解析的,因为其不知道name和getName()对应什么意思 当表达式是基于某一个对象时,我们可以把对应的对象作为一个rootObject传递给对应的Experssion进行取值 通过指定EvaluationContext我们可以让name和getName()变得有意义,指定了Ev

    2024年02月02日
    浏览(47)
  • spring AOP中pointcut表达式详解

    📢📢📢📣📣📣 哈喽!大家好,我是「奇点」,江湖人称 singularity。刚工作几年,想和大家一同进步🤝🤝 一位上进心十足的【Java ToB端大厂领域博主】!😜😜😜 喜欢java和python,平时比较懒,能用程序解决的坚决不手动解决😜😜😜 ✨ 如果有对【java】感兴趣的【小可

    2024年02月13日
    浏览(40)
  • 揭秘Spring依赖注入和SpEL表达式

    摘要: 在本文中,我们深入探讨了Spring框架中的属性注入技术,包括setter注入、构造器注入、注解式属性注入,以及使用SpEL表达式进行属性注入。 本文分享自华为云社区《Spring高手之路3——揭秘Spring依赖注入和SpEL表达式》,作者:砖业洋__ 。 在本文中,我们深入探讨了

    2024年02月08日
    浏览(39)
  • Java lambda表达式如何自定义一个toList Collector

    匿名类: Combiner: 应用: 优化初始容器的容量: Jdk toList默认实现:

    2024年02月01日
    浏览(41)
  • 深入理解Spring EL表达式的高级功能

    欢迎来到我的博客,代码的世界里,每一行都是一个故事 EL表达式不仅仅局限于基础用法,它还提供了丰富的高级功能。在这篇博客中,我们将揭开这些功能的神秘面纱,让你成为EL表达式的真正大师。 在EL(Expression Language)表达式中,可以使用各种操作符和语法来操作集合

    2024年01月25日
    浏览(45)
  • javaee spring aop 切入点表达式

    1、切入点表达式:对指定的方法进行拦截,并且生成代理表达式。 2、表达式不同写法 1.匹配指定方法 1 aop:pointcut expression=\\\"execution( public void com.test.service.impl.UsersService.add())\\\" id=\\\"pt\\\"/ 2.默认 public 可以省略 2 aop:pointcut expression=\\\"execution( void com.test.service.impl.UsersService.add())\\\" id=“p

    2024年02月10日
    浏览(47)
  • Spring高手之路3——揭秘Spring依赖注入和SpEL表达式

    本篇会给大家举出各种 Spring 属性依赖注入的例子,方便大家理解。 我们在前面的文章中已经使用过 XML 进行 setter 方法的属性注入了,下面让我们再来回顾一下: 我们在前面的文章中也学习过如何在 bean 创建时通过编程方式设置属性: 使用XML进行setter方法注入 首先,我们需

    2024年02月08日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包