返回顶部
首页 > 资讯 > 精选 >Spring Security中粒度超细的权限控制怎么实现
  • 749
分享到

Spring Security中粒度超细的权限控制怎么实现

2023-06-19 12:06:54 749人浏览 独家记忆
摘要

这篇文章主要讲解了“spring Security中粒度超细的权限控制怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring Security中粒度超细的权限控制怎么实现”吧!1

这篇文章主要讲解了“spring Security中粒度超细的权限控制怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring Security中粒度超细的权限控制怎么实现”吧!

1.准备工作

首先创建一个 Spring Boot 项目,由于我们这里涉及到数据库操作,所以除了 Spring Security 依赖之外,还需要加入数据库驱动以及 mybatis 依赖。

由于没有 acl 相关的 starter,所以需要我们手动添加 acl 依赖,另外 acl 还依赖于 ehcache 缓存,所以还需要加上缓存依赖。

最终的 pom.xml 文件如下:

<dependency>    <groupid>org.springframework.boot</groupid>    <artifactid>spring-boot-starter-security</artifactid></dependency><dependency>    <groupid>org.springframework.boot</groupid>    <artifactid>spring-boot-starter-WEB</artifactid></dependency><dependency>    <groupid>org.springframework.security</groupid>    <artifactid>spring-security-acl</artifactid>    <version>5.3.4.RELEASE</version></dependency><dependency>    <groupid>org.mybatis.spring.boot</groupid>    <artifactid>mybatis-spring-boot-starter</artifactid>    <version>2.1.3</version></dependency><dependency>    <groupid>mysql</groupid>    <artifactid>Mysql-connector-java</artifactid></dependency><dependency>    <groupid>net.sf.ehcache</groupid>    <artifactid>ehcache</artifactid>    <version>2.10.4</version></dependency><dependency>    <groupid>com.alibaba</groupid>    <artifactid>druid-spring-boot-starter</artifactid>    <version>1.1.23</version></dependency><dependency>    <groupid>org.springframework</groupid>    <artifactid>spring-context-support</artifactid></dependency>

项目创建成功之后,我们在 acl 的 jar 包中可以找到数据库脚本文件:

Spring Security中粒度超细的权限控制怎么实现

根据自己的数据库选择合适的脚本执行,执行后一共创建了四张表,如下:

Spring Security中粒度超细的权限控制怎么实现

表的含义我就不做过多解释了,不清楚的小伙伴可以参考上篇文章:Spring Security 中如何细化权限粒度?

最后,再在项目的 application.properties 文件中配置数据库信息,如下:

spring.datasource.url=jdbc:mysql:///acls?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghaispring.datasource.username=rootspring.datasource.passWord=123spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

至此,准备工作就算完成了。接下来我们来看配置。

2.ACL 配置

这块配置代码量比较大,我先把代码摆上来,我们再逐个分析:

@Configuration@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)public class AclConfig {    @Autowired    DataSource dataSource;    @Bean    public AclAuthorizationStrategy aclAuthorizationStrategy() {        return new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_ADMIN"));    }    @Bean    public PermissionGrantingStrategy permissionGrantingStrategy() {        return new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger());    }    @Bean    public AclCache aclCache() {        return new EhCacheBasedAclCache(aclEhCacheFactoryBean().getObject(), permissionGrantingStrategy(), aclAuthorizationStrategy());    }    @Bean    public EhCacheFactoryBean aclEhCacheFactoryBean() {        EhCacheFactoryBean ehCacheFactoryBean = new EhCacheFactoryBean();        ehCacheFactoryBean.setCacheManager(aclCacheManager().getObject());        ehCacheFactoryBean.setCacheName("aclCache");        return ehCacheFactoryBean;    }    @Bean    public EhCacheManagerFactoryBean aclCacheManager() {        return new EhCacheManagerFactoryBean();    }    @Bean    public LookupStrategy lookupStrategy() {        return new BasicLookupStrategy(dataSource, aclCache(), aclAuthorizationStrategy(), new ConsoleAuditLogger()        );    }    @Bean    public AclService aclService() {        return new JdbcMutableAclService(dataSource, lookupStrategy(), aclCache());    }    @Bean    PermissionEvaluator permissionEvaluator() {        AclPermissionEvaluator permissionEvaluator = new AclPermissionEvaluator(aclService());        return permissionEvaluator;    }}
  1. @EnableGlobalMethodSecurity 注解的配置表示开启项目中 @PreAuthorize、@PostAuthorize 以及 @Secured 注解的使用,一会我们要通过这些注解配置权限。

  2. 由于引入了数据库的一整套东西,并且配置了数据库连接信息,所以这里可以注入 DataSource 实例以备后续使用。

  3. AclAuthorizationStrategy 实例用来判断当前的认证主体是否有修改 Acl 的权限,准确来说是三种权限:修改 Acl 的 owner;修改 Acl 的审计信息以及修改 ACE 本身。这个接口只有一个实现类就是 AclAuthorizationStrategyImpl,我们在创建实例时,可以传入三个参数,分别对应了这三种权限,也可以传入一个参数,表示这一个角色可以干三件事。

  4. PermissionGrantingStrategy 接口提供了一个 isGranted 方法,这个方法就是最终真正进行权限比对的方法,该接口只有一个实现类 DefaultPermissionGrantingStrategy,直接 new 就行了。

  5. 在 ACL 体系中,由于权限比对总是要查询数据库,造成了性能问题,因此引入了 Ehcache 做缓存。AclCache 共有两个实现类:SprinGCacheBasedAclCache 和 EhCacheBasedAclCache。我们前面已经引入了 ehcache 实例,所以这里配置 EhCacheBasedAclCache 实例即可。

  6. LookupStrategy 可以通过 ObjectIdentity 解析出对应的 Acl。LookupStrategy 只有一个实现类就是 BasicLookupStrategy,直接 new 即可。

  7. AclService 这个我们在上文已经介绍过了,这里不再赘述。

  8. PermissionEvaluator 是为表达式 hasPermission 提供支持的。由于本案例后面使用类似于 @PreAuthorize("hasPermission(#noticeMessage, 'WRITE')") 这样的注解进行权限控制,因此之类需要配置一个 PermissionEvaluator 实例。

至此,这里的配置类就和大家介绍完了。

3.情节设定

假设我现在有一个通知消息类 NoticeMessage,如下:

public class NoticeMessage {    private Integer id;    private String content;    @Override    public String toString() {        return "NoticeMessage{" +                "id=" + id +                ", content='" + content + '\'' +                '}';    }    public Integer getId() {        return id;    }    public void setId(Integer id) {        this.id = id;    }    public String getContent() {        return content;    }    public void setContent(String content) {        this.content = content;    }}

然后根据该类创建了数据表:

CREATE TABLE `system_message` (  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,  `content` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

那么接下来的权限控制就是针对这个 NoticeMessage 的。

创建 NoticeMessageMapper,并添加几个测试方法:

@Mapperpublic interface NoticeMessageMapper {    List<noticemessage> findAll();    NoticeMessage findById(Integer id);    void save(NoticeMessage noticeMessage);    void update(NoticeMessage noticeMessage);}

NoticeMessageMapper.xml 内容如下:

<mapper namespace="org.javaboy.acls.mapper.NoticeMessageMapper">    <select id="findAll" resulttype="org.javaboy.acls.model.NoticeMessage">        select * from system_message;    </select>    <select id="findById" resulttype="org.javaboy.acls.model.NoticeMessage">        select * from system_message where id=#{id};    </select>    <insert id="save" parametertype="org.javaboy.acls.model.NoticeMessage">        insert into system_message (id,content) values (#{id},#{content});    </insert>    <update id="update" parametertype="org.javaboy.acls.model.NoticeMessage">        update system_message set content = #{content} where id=#{id};    </update></mapper>

这些应该都好理解,没啥好说的。

接下来创建 NoticeMessageService,如下:

@Servicepublic class NoticeMessageService {    @Autowired    NoticeMessageMapper noticeMessageMapper;    @PostFilter("hasPermission(filterObject, 'READ')")    public List<noticemessage> findAll() {        List<noticemessage> all = noticeMessageMapper.findAll();        return all;    }    @PostAuthorize("hasPermission(returnObject, 'READ')")    public NoticeMessage findById(Integer id) {        return noticeMessageMapper.findById(id);    }    @PreAuthorize("hasPermission(#noticeMessage, 'CREATE')")    public NoticeMessage save(NoticeMessage noticeMessage) {        noticeMessageMapper.save(noticeMessage);        return noticeMessage;    }        @PreAuthorize("hasPermission(#noticeMessage, 'WRITE')")    public void update(NoticeMessage noticeMessage) {        noticeMessageMapper.update(noticeMessage);    }}

涉及到了两个新注解,稍微说下:

  • @PostFilter:在执行方法后过滤返回的集合数组(筛选出当前用户具有 READ 权限的数据),returnObject 就表示方法的返回值。有一个和它对应的注解 @PreFilter,这个注解允许方法调用,但必须在进入方法之前对参数进行过滤。

  • @PostAuthorize:允许方法调用,但是如果表达式计算结果为false,将抛出一个安全性异常,#noticeMessage 对应了方法的参数。

  • @PreAuthorize:在方法调用之前,基于表达式的计算结果来限制对方法的访问。

明白了注解的含义,那么上面的方法应该就不用多做解释了吧。

配置完成,接下来我们进行测试。

4.测试

为了方便测试,我们首先准备几条测试数据,如下:

INSERT INTO `acl_class` (`id`, `class`)VALUES(1,'org.javaboy.acls.model.NoticeMessage');INSERT INTO `acl_sid` (`id`, `principal`, `sid`)VALUES(2,1,'hr'),(1,1,'manager'),(3,0,'ROLE_EDITOR');INSERT INTO `system_message` (`id`, `content`)VALUES(1,'111'),(2,'222'),(3,'333');

首先添加了 acl_class,然后添加了三个 Sid,两个是用户,一个是角色,最后添加了三个 NoticeMessage 实例。

目前没有任何用户/角色能够访问到 system_message 中的三条数据。例如执行如下代码获取不到任何数据:

@Test@WithMockUser(roles = "EDITOR")public void test01() {    List<noticemessage> all = noticeMessageService.findAll();    System.out.println("all = " + all);}

> @WithMockUser(roles = "EDITOR") 表示使用 EDITOR 角色访问。松哥这里是为了方便。小伙伴们也可以自己给 Spring Security 配置用户,设置相关接口,然后 Controller 中添加接口进行测试,我这里就不那么麻烦了。

现在我们对其进行配置。

首先我想设置让 hr 这个用户可以读取 system_message 表中 id 为 1 的记录,方式如下:

@AutowiredNoticeMessageService noticeMessageService;@AutowiredJdbcMutableAclService jdbcMutableAclService;@Test@WithMockUser(username = "javaboy")@Transactional@Rollback(value = false)public void test02() {    ObjectIdentity objectIdentity = new ObjectIdentityImpl(NoticeMessage.class, 1);    Permission p = BasePermission.READ;    MutableAcl acl = jdbcMutableAclService.createAcl(objectIdentity);    acl.insertAce(acl.getEntries().size(), p, new PrincipalSid("hr"), true);    jdbcMutableAclService.updateAcl(acl);}

我们设置了 mock user 是 javaboy,也就是这个 acl 创建好之后,它的 owner 是 javaboy,但是我们前面预设数据中 Sid 没有 javaboy,所以会自动向 acl_sid 表中添加一条记录,值为 javaboy。

在这个过程中,会分别向 acl_entry、acl_object_identity 以及 acl_sid 三张表中添加记录,因此需要添加事务,同时因为我们是在单元测试中执行,为了确保能够看到数据库中数据的变化,所以需要添加 @Rollback(value = false) 注解让事务不要自动回滚。

在方法内部,首先分别创建 ObjectIdentity 和 Permission 对象,然后创建一个 acl 对象出来,这个过程中会将 javaboy 添加到 acl_sid 表中。

接下来调用 acl_insertAce 方法,将 ace 存入 acl 中,最后调用 updateAcl 方法去更新 acl 对象即可。

配置完成后,执行该方法,执行完成后,数据库中就会有相应的记录了。

接下来,使用 hr 这个用户就可以读取到 id 为 1 的记录了。如下:

@Test@WithMockUser(username = "hr")public void test03() {    List<noticemessage> all = noticeMessageService.findAll();    assertNotNull(all);    assertEquals(1, all.size());    assertEquals(1, all.get(0).getId());    NoticeMessage byId = noticeMessageService.findById(1);    assertNotNull(byId);    assertEquals(1, byId.getId());}

松哥这里用了两个方法来和大家演示。首先我们调用了 findAll,这个方法会查询出所有的数据,然后返回结果会被自动过滤,只剩下 hr 用户具有读取权限的数据,即 id 为 1 的数据;另一个调用的就是 findById 方法,传入参数为 1,这个好理解。

如果此时想利用 hr 这个用户修改对象,则是不可以的。我们可以继续使用上面的代码,让 hr 这个用户可以修改 id 为 1 的记录,如下:

@Test@WithMockUser(username = "javaboy")@Transactional@Rollback(value = false)public void test02() {    ObjectIdentity objectIdentity = new ObjectIdentityImpl(NoticeMessage.class, 1);    Permission p = BasePermission.WRITE;    MutableAcl acl = (MutableAcl) jdbcMutableAclService.readAclById(objectIdentity);    acl.insertAce(acl.getEntries().size(), p, new PrincipalSid("hr"), true);    jdbcMutableAclService.updateAcl(acl);}

注意这里权限改为 WRITE 权限。由于 acl 中已经存在这个 ObjectIdentity 了,所以这里通过 readAclById 方法直接读取已有的 acl 即可。方法执行完毕后,我们再进行 hr 用户写权限的测试:

@Test@WithMockUser(username = "hr")public void test04() {    NoticeMessage msg = noticeMessageService.findById(1);    assertNotNull(msg);    assertEquals(1, msg.getId());    msg.setContent("javaboy-1111");    noticeMessageService.update(msg);    msg = noticeMessageService.findById(1);    assertNotNull(msg);    assertEquals("javaboy-1111", msg.getContent());}

此时,hr 就可以使用 WRITE 权限去修改对象了。

假设我现在想让 manager 这个用户去创建一个 id 为 99 的 NoticeMessage,默认情况下,manager 是没有这个权限的。我们现在可以给他赋权:

@Test@WithMockUser(username = "javaboy")@Transactional@Rollback(value = false)public void test02() {    ObjectIdentity objectIdentity = new ObjectIdentityImpl(NoticeMessage.class, 99);    Permission p = BasePermission.CREATE;    MutableAcl acl = jdbcMutableAclService.createAcl(objectIdentity);    acl.insertAce(acl.getEntries().size(), p, new PrincipalSid("manager"), true);    jdbcMutableAclService.updateAcl(acl);}

注意,这里的权限是 CREATE。

接下来使用 manager 用户就可以添加数据了:

@Test@WithMockUser(username = "manager")public void test05() {    NoticeMessage noticeMessage = new NoticeMessage();    noticeMessage.setId(99);    noticeMessage.setContent("999");    noticeMessageService.save(noticeMessage);}

此时就可以添加成功了。

感谢各位的阅读,以上就是“Spring Security中粒度超细的权限控制怎么实现”的内容了,经过本文的学习后,相信大家对Spring Security中粒度超细的权限控制怎么实现这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: Spring Security中粒度超细的权限控制怎么实现

本文链接: https://lsjlt.com/news/296056.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Spring Security中粒度超细的权限控制怎么实现
    这篇文章主要讲解了“Spring Security中粒度超细的权限控制怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring Security中粒度超细的权限控制怎么实现”吧!1...
    99+
    2023-06-19
  • Spring Security权限控制的接口怎么实现
    本篇内容主要讲解“Spring Security权限控制的接口怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Spring Security权限控制的接口怎么实现”吧!...
    99+
    2023-07-05
  • Spring Security权限管理实现接口动态权限控制
    目录摘要前置知识数据库设计数据库表结构数据库表介绍ums_adminums_roleums_admin_role_relationums_menuums_resourceums_re...
    99+
    2024-04-02
  • Kubernetes Ingress怎么实现细粒度IP访问控制
    这篇“Kubernetes Ingress怎么实现细粒度IP访问控制”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“...
    99+
    2023-07-06
  • Spring Security实现统一登录与权限控制的示例代码
    目录项目介绍统一认证中心配置授权服务器配置WebSecurity登录菜单鉴权资源访问的一些配置有用的文档项目介绍 最开始是一个单体应用,所有功能模块都写在一个项目里,后来觉得项目越来...
    99+
    2024-04-02
  • Linux中的超级权限怎么控制
    在Linux中,超级权限是指root用户拥有的特权,可以对系统的所有资源和文件进行完全的控制和操作。为了确保系统的安全性,有以下控制...
    99+
    2023-10-23
    Linux
  • Spring Security中的四种权限控制方式分别是什么
    本篇文章为大家展示了Spring Security中的四种权限控制方式分别是什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Spring Security 中对于...
    99+
    2024-04-02
  • javaweb设计中filter粗粒度权限控制的示例分析
    小编给大家分享一下javaweb设计中filter粗粒度权限控制的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!1 说明我们给出三个页面:index.jsp、user.jsp、admin.jsp。index.jsp...
    99+
    2023-05-31
    javaweb filter
  • mysql 中怎么实现权限控制
    本篇文章给大家分享的是有关mysql 中怎么实现权限控制,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。概述mysql权限控制在不同的上下文和不...
    99+
    2024-04-02
  • Vue2.0中怎么实现用户权限控制
    这篇文章将为大家详细讲解有关Vue2.0中怎么实现用户权限控制,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。运行//开发 npm run ...
    99+
    2024-04-02
  • CRM Transaction处理中的权限控制怎么实现
    本篇内容主要讲解“CRM Transaction处理中的权限控制怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“CRM Transaction处理中的权限控制怎么实现”吧!当试图打开一个O...
    99+
    2023-06-04
  • Spring Security实现基于RBAC的权限表达式动态访问控制的操作方法
    目录资源权限表达式Spring Security中的实现MethodSecurityExpressionHandler思路以及实现配置和使用昨天有个粉丝加了我,问我如何实现类似shi...
    99+
    2024-04-02
  • MLSQL中怎么实现编译时权限控制
    本篇文章为大家展示了MLSQL中怎么实现编译时权限控制,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。权限控制,对于MLSQL而言的重要程度可以说是生命线。 MLSQ...
    99+
    2024-04-02
  • vue按钮怎么实现权限控制
    这篇文章主要讲解了“vue按钮怎么实现权限控制”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“vue按钮怎么实现权限控制”吧!一、步骤1.定义buttom权限在state中创建buttomPe...
    99+
    2023-06-22
  • Springboot+Spring Security实现前后端分离登录认证及权限控制的示例代码
    目录前言本文主要的功能 一、准备工作1、统一错误码枚举2、统一json返回体3、返回体构造工具4、pom5、配置文件二、数据库表设计初始化表数据语句三、Spring Sec...
    99+
    2024-04-02
  • springcloud-gateway整合jwt+jcasbin实现权限控制的详细过程
    目录jcasbin简介:jcasbin 的主要特性包括:jcasbin 不做的事情:项目架构:父pom文件:gateway项目:pom文件:gateway相关核心代码:admin-u...
    99+
    2023-02-07
    springcloud-gateway整合jwt+jcasbin springcloud-gateway权限控制
  • Spring Security基于注解的接口角色访问控制怎么实现
    本文小编为大家详细介绍“Spring Security基于注解的接口角色访问控制怎么实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring Security基于注解的接口角色访问控制怎么实现”文章能帮助大家解决疑惑,下面跟着小编的...
    99+
    2023-06-16
  • vue-router中怎么实现路由懒加载和权限控制
    今天就跟大家聊聊有关vue-router中怎么实现路由懒加载和权限控制,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。1、为什么要使用路由懒加载呢用v...
    99+
    2024-04-02
  • 怎么使用MyBatisPlus拦截器实现数据权限控制
    这篇文章主要介绍“怎么使用MyBatisPlus拦截器实现数据权限控制”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“怎么使用MyBatisPlus拦截器实现数据权限控制”文章能帮助大家解决问题。前言...
    99+
    2023-07-05
  • laravel怎么实现非法登录和权限控制功能
    本篇内容介绍了“laravel怎么实现非法登录和权限控制功能”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1、首先我们打开artisan输入...
    99+
    2023-07-04
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作