vlambda博客
学习文章列表

读书笔记《spring-security-third-edition》访问控制列表

访问控制列表

在本章中,我们将讨论访问控制列表(ACL)这个复杂的主题,它可以提供丰富的域对象实例级授权模型。 Spring Security 附带了一个健壮但复杂的访问控制列表模块,可以很好地满足中小型实现的需求。

在本章中,我们将介绍以下主题:

  • Understanding the conceptual model of ACL
  • Reviewing the terminology and application of ACL concepts in the Spring Security ACL module
  • Building and reviewing the database schema required to support Spring ACL
  • Configuring JBCP calendar to use ACL secured business methods via annotations and Spring beans
  • Performing advanced configuration, including customized ACL permissions, ACL-enabled JSP tag checks and method security, mutable ACLs, and smart caching
  • Examining architectural considerations and planning scenarios for ACL deployment

ACL的概念模块

非 Web 层安全难题的最后一块是业务对象级别的安全性,应用于业务层或业务层以下。此级别的安全性是使用称为 ACL 或 ACL 的技术实现的。一句话总结 ACL 的目标——ACL 允许基于组、业务对象和逻辑操作的唯一组合来指定一组组权限。

例如,JBCP 日历的 ACL 声明可能声明给定用户必须对他或她自己的事件进行写访问。这可以显示如下:

用户名

对象

权限

米克

event_01

读取写入

ROLE_USER

event_123

阅读

匿名

任何事件

您可以看到这个 ACL 非常容易被人类阅读——mick 对他自己的事件(event_01< /kbd>);其他注册用户可以读取mick的事件,但匿名用户不能。简而言之,这种类型的规则矩阵就是 ACL 试图将安全系统及其业务数据综合成代码、访问检查和元数据的组合。大多数真正启用 ACL 的系统都具有极其复杂的 ACL 列表,并且可能在整个系统中拥有数百万个条目。尽管这听起来非常复杂,但适当的前期推理和使用功能强大的安全库实现可以使 ACL 管理变得非常可行。

如果您使用基于 Microsoft Windows 或 Unix/Linux 的计算机,那么您每天都会体验 ACL 的魔力。大多数现代计算机操作系统使用 ACL 指令作为其文件存储系统的一部分,允许基于用户或组、文件或目录以及权限的组合授予权限。在 Microsoft Windows 中,您可以通过右键单击文件并检查其安全属性(Properties | 安全性),如以下屏幕截图所示:

读书笔记《spring-security-third-edition》访问控制列表

当您浏览各种组或用户和权限时,您将能够看到 ACL 的输入组合是可见且直观的。

Spring Security 中的访问控制列表

Spring Security 支持 ACL 驱动的授权检查,以防止安全系统的单个用户访问单个域对象。就像在 OS 文件系统示例中一样,可以使用 Spring Security ACL 组件来构建业务对象和组或主体的逻辑树结构。请求者和被请求者的权限(继承的或显式的)的交集用于确定允许的访问。

对于接近 Spring Security 的 ACL 功能的用户来说,由于其复杂性以及相对缺乏文档和示例而不知所措是很常见的。更复杂的是,设置 ACL 基础设施可能非常复杂,有许多相互依赖和对基于 bean 的配置机制的依赖,这与 Spring Security 的其余部分完全不同(稍后您将看到我们设置了初始配置)。

Spring Security ACL 模块被编写为一个合理的基线,但是打算在该功能上广泛构建的用户可能会遇到一系列令人沮丧的限制和设计选择,这些限制和设计选择在首次引入时(大部分)没有得到纠正在 Spring Security 的早期。不要让这些限制让您灰心! ACL 模块是在您的应用程序中嵌入丰富的访问控制,并进一步审查和保护用户操作和数据的强大方式。

在深入研究配置 Spring Security ACL 支持之前,我们需要回顾一些关键术语和概念。

Spring ACL 系统中安全参与者身份的主要单位是Security Identity(SID)。 SID 是一种逻辑结构,可用于抽象单个主体或组的身份 (GrantedAuthority)。在确定特定主体的允许访问级别时,由您构造的 ACL 数据模型定义的 SIDs 对象用作显式和派生访问控制规则的基础。

如果 SIDs 用于定义 ACL 系统中的参与者,则安全方程式的另一半是安全对象本身的定义。单个安全对象的识别被称为(毫不奇怪)对象身份。对象标识的默认 Spring ACL 实现需要在单个对象实例级别定义 ACL 规则,这意味着,如果需要,系统中的每个对象都可以具有单独的访问规则。

单个访问规则称为访问控制条目 (ACE)。 ACE 是以下因素的组合:

  • The SID for the actor to which the rule applies
  • The object identity to which the rule applies
  • The permission that should be applied to the given SID and the stated object identity
  • Whether or not the stated permission should be allowed or denied for the given SID and object identity

Spring ACL 系统作为一个整体的目的是评估每个安全方法调用,并根据适用的 ACE 确定是否应允许在方法中作用的一个或多个对象。适用的 ACE 在运行时根据调用者和正在运行的对象进行评估。

Spring Security ACL 的实现很灵活。尽管本章的大部分内容都详细介绍了 Spring Security ACL 模块的开箱即用功能,但是请记住,许多指示的规则代表默认实现,在许多情况下可以基于更复杂的要求。

Spring Security 使用有用的值对象来表示与这些概念实体中的每一个相关联的数据。这些列在下表中:

ACL 概念对象

Java 对象

SID

o.s.s.acls.model.Sid

对象身份

o.s.s.acls.model.ObjectIdentity

访问控制列表

o.s.s.acls.model.Acl

高手

o.s.s.acls.model.AccessControlEntry

让我们完成启用 Spring Security ACL 组件的过程,以便在 JBCP 日历应用程序中进行简单演示。

Spring Security ACL 支持的基本配置

尽管我们之前暗示在 Spring Security 中配置 ACL 支持需要基于 bean 的配置(确实如此),但如果您愿意,您可以在保留更简单的安全 XML 命名空间配置的同时使用 ACL 支持。在本章的其余示例中,我们将重点关注基于 Java 的配置。

Gradle 依赖项

与大多数章节一样,我们需要添加一些依赖项才能使用本章中的功能。我们添加的依赖项列表以及何时需要它们的注释可以检查如下:

    build.gradle
    dependencies {
       // ACL
       compile('org.springframework.security:spring-security-acl')
      compile('net.sf.ehcache:ehcache')
       ...
    }

定义一个简单的目标场景

我们的简单目标场景是只授予 [email protected] 对生日派对事件的读取权限。所有其他用户将无权访问任何事件。您会发现这与我们的其他示例不同,因为 [email protected] 与生日聚会事件没有其他关联。

尽管有几种方法可以设置 ACL 检查,但我们还是倾向于遵循我们在本章方法级注释中使用的基于注释的方法。这很好地将 ACL 的使用从实际的接口声明中抽象出来,并允许在以后用 ACL 以外的东西替换角色声明(如果你愿意的话)(如果你这样选择的话)。

我们将向 CalendarService.getEvents 方法添加注释,该方法根据当前用户对事件的权限过滤每个事件:

    src/main/java/com/packtpub/springsecurity/service/CalendarService.java
    @PostFilter("hasPermission(filterObject, 'read')")
    List<Event> getEvents();
你应该从 第 12.00 章-日历

将 ACL 表添加到 H2 数据库

我们需要做的第一件事是添加所需的表和数据,以支持我们的内存 H2 数据库中的持久 ACL 条目。为此,我们将在 schema.sql 中的嵌入式数据库声明中添加一个新的 SQL DDL 文件和相应的数据。我们将在本章后面分解每个文件。

我们在本章的源代码中包含了以下 schema.sql 文件,该文件基于 Spring Security 参考附录附加参考资料中包含的模式文件:

src/main/resources/schema.sql
-- ACL Schema --
create table acl_sid (
id bigint generated by default as identity(start with 100) not
   null primary key,
principal boolean not null,
sid varchar_ignorecase(100) not null,
constraint uk_acl_sid unique(sid,principal) );

create table acl_class (
id bigint generated by default as identity(start with 100) not
   null primary key,
class varchar_ignorecase(500) not null,
constraint uk_acl_class unique(class) );

create table acl_object_identity (
id bigint generated by default as identity(start with 100) not
   null primary key,
object_id_class bigint not null,
object_id_identity bigint not null,
parent_object bigint,
owner_sid bigint not null,
entries_inheriting boolean not null,
constraint uk_acl_objid
   unique(object_id_class,object_id_identity),
constraint fk_acl_obj_parent foreign
   key(parent_object)references acl_object_identity(id),
constraint fk_acl_obj_class foreign
   key(object_id_class)references acl_class(id),
constraint fk_acl_obj_owner foreign key(owner_sid)references
   acl_sid(id) );

create table acl_entry (
id bigint generated by default as identity(start with 100) not
   null primary key,
acl_object_identity bigint not null,
ace_order int not null,
sid bigint not null,
mask integer not null,
granting boolean not null,
audit_success boolean not null,
audit_failure boolean not null,
constraint uk_acl_entry unique(acl_object_identity,ace_order),
constraint fk_acl_entry_obj_id foreign key(acl_object_identity)
references acl_object_identity(id),
constraint fk_acl_entry_sid foreign key(sid) references
   acl_sid(id) );

前面的代码将产生以下数据库模式:

读书笔记《spring-security-third-edition》访问控制列表

您可以看到 SIDOBJECT_IDENTITY 和 ACE 的概念如何直接映射到数据库模式。从概念上讲,这很方便,因为我们可以将 ACL 系统的心智模型以及它如何直接执行到数据库中。

如果您已将其与 Spring Security 文档提供的 H2 数据库模式交叉引用,您会注意到我们进行了一些通常会咬用户的调整。这些如下:

  • Change the ACL_CLASS.CLASS column to 500 characters, from the default value of 100. Some long, fully qualified class names don't fit in 100 characters.
  • Name the foreign keys with something meaningful so that failures are more easily diagnosed.

如果您使用的是其他数据库,例如 Oracle,则必须将 DDL 转换为特定于您的数据库的 DDL 和数据类型。

配置完 ACL 系统的其余部分后,我们将返回数据库设置一些基本的 ACE,以最原始的形式证明 ACL 的功能。

配置 SecurityExpressionHandler

我们需要配置 <global-method-security> 以启用注释(我们将根据预期的 ACL 权限进行注释),并引用自定义访问决策管理器。

我们还需要提供一个知道如何评估权限的 o.s.s.access.expression.SecurityExpressionHandler 实现。更新您的 SecurityConfig.java 配置,如下所示:

    src/main/java/com/packtpub/springsecurity/configuration/SecurityConfig.java 
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    @Import(AclConfig.class)
    public class SecurityConfig extends WebSecurityConfigurerAdapter {

这是我们在 AclConfig.java 文件中为您定义的 DefaultMethodSecurityExpressionHandler 对象的 bean 引用,如下所示:

    src/main/java/com/packtpub/springsecurity/configuration/AclConfig.java
    @Bean
    public DefaultMethodSecurityExpressionHandler expressionHandler(){
       DefaultMethodSecurityExpressionHandler dmseh =
       new DefaultMethodSecurityExpressionHandler();
      dmseh.setPermissionEvaluator(permissionEvaluator());
       dmseh.setPermissionCacheOptimizer(permissionCacheOptimizer());
       return dmseh; 
    }

即使是相对简单的 ACL 配置,就像我们在我们的场景中那样,也需要设置许多必需的依赖项。正如我们之前提到的,Spring Security ACL 模块是开箱即用的,带有许多组件,您可以组装这些组件以提供一组不错的 ACL 功能。请注意,我们将在下图中引用的所有组件都是框架的一部分:

读书笔记《spring-security-third-edition》访问控制列表

AclPermissionCacheOptimizer 对象

DefaultMethodSecurityExpressionHandler 对象有两个依赖项。 AclPermissionCacheOptimizer 对象用于为单个 JDBC 选择语句中的对象集合的所有 ACL 填充缓存。本章包含的比较简单的配置可以查看,如下:

     src/main/java/com/packtpub/springsecurity/configuration/AclConfig.java
     @Bean
    public AclPermissionCacheOptimizer permissionCacheOptimizer(){
       return new AclPermissionCacheOptimizer(aclService());
    }

优化 AclPermission 缓存

DefaultMethodSecurityExpressionHandler 对象然后委托给 PermissionEvalulator 实例。出于本章的目的,我们使用 ACL,以便我们将使用 AclPermissionEvaluator 的 bean,它将读取我们在数据库中定义的 ACL。您可以查看为 permissionEvaluator 提供的配置,如下所示:

src/main/java/com/packtpub/springsecurity/configuration/AclConfig.java
@Bean
public AclPermissionEvaluator permissionEvaluator(){
   return new AclPermissionEvaluator(aclService());
}

JdbcMutableAclService 对象

在这一点上,我们已经看到两次以 aclService ID 对 th 的引用。 aclService ID 解析为 o.s.s.acls.model.AclService 的实现,该实现负责(通过委托)将有关受 ACL 保护的对象的信息转换为预期的 ACE:

src/main/java/com/packtpub/springsecurity/configuration/AclConfig.java
@Autowired 
private DataSource dataSource;
@Bean
public JdbcMutableAclService aclService(){
   return new JdbcMutableAclService(dataSource,
                                     lookupStrategy(),
                                     aclCache());
}

我们将使用 o.s.s.acls.jdbc.JdbcMutableAclService,它是 o.s.s.acls.model.AclService 的默认实现。此实现开箱即用,可以使用我们在本练习的最后一步中定义的模式。 JdbcMutableAclService 对象将另外使用递归 SQL 和后处理来了解对象和 SID 层次结构,并确保将这些层次结构的表示传递回 AclPermissionEvaluator

BasicLookupStrategy 类

JdbcMutableAclService 类使用我们使用嵌入式数据库声明定义的相同 JDBC dataSource 实例,它还委托给 o.s.s.acls.jdbc 的实现。 LookupStrategy,它单独负责实际进行数据库查询和解析 ACL 请求。 Spring Security 提供的唯一 LookupStrategy 实现是 o.s.s.acls.jdbc.BasicLookupStrategy,定义如下:

src/main/java/com/packtpub/springsecurity/configuration/AclConfig.java
@Bean
public LookupStrategy lookupStrategy(){
   return new BasicLookupStrategy(
           dataSource,
           aclCache(),
           aclAuthorizationStrategy(),
           consoleAuditLogger());
}

现在,BasicLookupStrategy 是一个相对复杂的野兽。请记住,它的目的是将要保护的 ObjectIdentity 声明列表转换为来自数据库的实际适用的 ACE 列表。由于 ObjectIdentity 声明可以是递归的,这被证明是一个非常具有挑战性的问题,并且可能会经历大量使用的系统应该考虑为对数据库的性能影响而生成的 SQL。

用最小公分母查询

请注意,BasicLookupStrategy 旨在通过严格遵守标准 ANSI SQL 语法(尤其是 left [outer] joins)与所有数据库兼容。一些较旧的数据库(特别是 Oracle8i)不支持这种连接语法,因此请确保您验证 SQL 的语法和结构与您的特定数据库兼容!

当然还有更有效的依赖数据库的方法来使用非标准 SQL 执行分层查询,例如 Oracle 的 CONNECT BY 语句和 Common Table Expression(CTE) 许多其他数据库的功能,包括 PostgreSQL 和 Microsoft SQL Server。

正如您在 第 4 章中的示例中学到的,JDBC -Based Authentication,使用 UserDetailsS​​ervice 属性的 JdbcDaoImpl 实现的自定义模式,以允许配置 BasicLookupStrategy< /kbd>。请查阅 Javadoc 和源代码本身以了解它们是如何使用的,以便它们可以正确地应用于您的自定义模式。

我们可以看到 LookupStrategy 需要引用 AclService 使用的同一个 JDBC dataSource 实例。其他三个引用几乎将我们带到了依赖链的末端。

EhCacheBasedAclCache

o.s.s.acls.model.AclCache 接口声明了一个用于将 ObjectIdentity 缓存到 ACL 映射的接口,以防止冗余(和昂贵的)数据库查找。 Spring Security 仅附带了一个 AclCache 实现,使用第三方库 Ehcache

Ehcache 是一个开源的、基于内存和磁盘的缓存库,广泛用于许多开源和商业 Java 产品中。正如本章前面提到的,Spring Security 附带了 ACL 缓存的默认实现,它依赖于配置的 Ehcache 实例的可用性,它使用该实例来存储 ACL 信息,而不是从数据库。

虽然 Ehcache 的深度配置不是我们想要在本节中介绍的内容,但我们将介绍 Spring ACL 如何使用缓存并引导您完成基本的默认配置。

设置 Ehcache 很简单——我们只需声明 o.s.s.acls.domain.EhCacheBasedAclCache 及其来自 Spring Core 的两个依赖 bean,它们管理 Ehcache实例化并公开几个有用的配置属性。和我们的其他 bean 一样,我们已经在 AclConfig.java 中提供了以下配置:

src/main/java/com/packtpub/springsecurity/configuration/AclConfig.java
@Bean
public EhCacheBasedAclCache aclCache(){
   return new EhCacheBasedAclCache(ehcache(),
           permissionGrantingStrategy(),
           aclAuthorizationStrategy()
           );
}

@Bean
public PermissionGrantingStrategy permissionGrantingStrategy(){
   return new DefaultPermissionGrantingStrategy(consoleAuditLogger());
}

@Bean
public Ehcache ehcache(){
   EhCacheFactoryBean cacheFactoryBean = new EhCacheFactoryBean();
   cacheFactoryBean.setCacheManager(cacheManager());
   cacheFactoryBean.setCacheName("aclCache");
   cacheFactoryBean.setMaxBytesLocalHeap("1M");
   cacheFactoryBean.setMaxEntriesLocalHeap(0L);
   cacheFactoryBean.afterPropertiesSet();
   return cacheFactoryBean.getObject();
}

@Bean
public CacheManager cacheManager(){
   EhCacheManagerFactoryBean cacheManager = new EhCacheManagerFactoryBean();
   cacheManager.setAcceptExisting(true);   cacheManager.setCacheManagerName(CacheManager.getInstance().getName());
   cacheManager.afterPropertiesSet();
return cacheManager.getObject();
}

ConsoleAuditLogger 类

o.s.s.acls.jdbc.BasicLookupStrategy 的下一个简单依赖是 o.s.s.acls.domain.AuditLogger 接口的实现,该接口由 BasicLookupStrategy< /kbd> 类来审核 ACL 和 ACE 查找。与 AclCache 接口类似,Spring Security 只提供了一种实现,它只是简单地记录到控制台。我们将使用另一个单行 bean 声明对其进行配置:

src/main/java/com/packtpub/springsecurity/configuration/AclConfig.java
@Bean
public ConsoleAuditLogger consoleAuditLogger(){
   return new ConsoleAuditLogger();
}

AclAuthorizationStrategyImpl 接口

最后要解决的依赖是 o.s.s.acls.domain.AclAuthorizationStrategy 接口的实现,在从数据库加载 ACL 期间,它实际上根本没有直接责任。相反,此接口的实现负责根据更改的类型确定是否允许对 ACL 或 ACE 进行运行时更改。稍后我们将在讨论可变 ACL 时对此进行更多解释,因为逻辑流程有点复杂,并且与完成我们的初始配置无关。最终配置要求如下:

src/main/java/com/packtpub/springsecurity/configuration/AclConfig.java
@Bean
public AclAuthorizationStrategy aclAuthorizationStrategy() {
   return new AclAuthorizationStrategyImpl(
           new SimpleGrantedAuthority("ROLE_ADMINISTRATOR")
   );
}

您可能想知道对 ID 为 adminAuthority 的 bean 的引用是为了什么 - AclAuthorizationStrategyImpl 提供了指定允许特定操作所需的 GrantedAuthority 的能力在运行时在可变 ACL 上。我们将在本章后面介绍这些内容。

最后,我们需要更新我们的 SecurityConfig.java 文件以加载我们的 AclConfig.java 文件,如下所示:

src/main/java/com/packtpub/springsecurity/configuration/SecurityConfig.java
@Import(AclConfig.class)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

我们终于完成了开箱即用的 Spring Security ACL 实现的基本配置。下一步也是最后一步,我们需要将一个简单的 ACL 和 ACE 插入 H2 数据库并进行测试!

创建一个简单的 ACL 条目

回想一下,我们非常简单的场景是只允许 [email protected] 访问生日聚会事件,并确保没有其他事件可以访问。您可能会发现参考数据库模式图的几页以了解我们要插入哪些数据以及为什么插入会很有帮助。

我们已经在示例应用程序中包含了一个名为 data.sql 的文件。本节中解释的所有 SQL 都来自该文件——您可以根据我们提供的示例 SQL 随意试验和添加更多测试用例——事实上,我们鼓励您使用示例数据进行试验!

让我们看一下创建简单 ACL 条目的以下步骤:

  1. First, we'll need to populate the ACL_CLASS table with any or all of the domain object classes, which may have ACL rules—in the case of our example, this is simply our Event class:
        src/main/resources/data.sql
        insert into acl_class (id, class) values (10, 
        'com.packtpub.springsecurity.domain.Event');

对于 ACL_CLASS 表,我们选择使用 1019 之间的主键,20 29 用于 ACL_SID 表,依此类推。这将有助于更容易理解哪些数据与哪个表相关联。请注意,我们的 Event 表以 100 的主键开始。这些便利是出于示例目的,不建议用于生产目的。

  1. Next, the ACL_SID table is seeded with SIDs that will be associated with the ACEs. Remember that SIDs can either be roles or users—we'll populate the roles and [email protected] here.
  2. While the SID object for roles is straightforward, the SID object for a user is not quite as clear-cut. For our purposes, the username is used for the SID. To learn more about how the SIDs are resolved for roles and users, refer to o.s.s.acls.domain.SidRetrievalStrategyImpl. If the defaults do not meet your needs, a custom o.s.s.acls.model.SidRetrievalStrategy default can be injected into AclPermissionCacheOptimizer and AclPermissionEvaluator. We will not need this sort of customization for our example, but it is good to know that it is available if necessary:
        src/main/resources/data.sql
        insert into acl_sid (id, principal, sid) values (20, true,  
        '[email protected]');
        insert into acl_sid (id, principal, sid) values (21, false, 
        'ROLE_USER');
        insert into acl_sid (id, principal, sid) values (22, false, 
        'ROLE_ADMIN');

事情开始变得复杂的表是 ACL_OBJECT_IDENTITY 表,用于声明各个域对象实例、它们的父级(如果有)和拥有 SID。例如,此表表示我们正在保护的 Event 对象。我们将插入具有以下属性的行:

  • Domain object of type Event that is a foreign key, 10, to our ACL_CLASS table via the OBJECT_ID_CLASS column.
  • Domain object primary key of 100 (the OBJECT_ID_IDENTITY column). This is a foreign key (although not enforced with a database constraint) to our Event object.
  • Owner SID of [email protected], which is a foreign key, 20, to ACL_SID via the OWNER_SID column.

表示我们的事件 ID 为 100(生日事件)、101102 的 SQL 如下:

    src/main/resources/data.sql
    insert into acl_object_identity(id,object_id_identity,object_id_class,
    parent_object,owner_sid,entries_inheriting)
    values (30, 100, 10, null, 20, false);
    insert into acl_object_identity(id,object_id_identity,object_id_class,
    parent_object,owner_sid,entries_inheriting) 
    values (31, 101, 10, null, 21, false);
    insert into acl_object_identity(id,object_id_identity,object_id_class,
    parent_object,owner_sid,entries_inheriting)
    values (32, 102, 10, null, 21, false);

请记住,拥有的 SID 也可以代表一个角色——就 ACL 系统而言,这两种类型的规则功能相同。

最后,我们将添加一个与此对象实例相关的 ACE,它声明允许 [email protected] 对生日事件进行读取访问:

    src/main/resources/data.sql
    insert into acl_entry
   (acl_object_identity, ace_order, sid, mask, granting, audit_success, 
   audit_failure) values(30, 1, 20, 1, true, true, true);

这里的MASK 列代表一个位掩码,用于授予分配给相关对象上所述SID 的权限。我们将在本章后面解释这方面的细节——不幸的是,它并不像听起来那么有用。

现在,我们可以启动应用程序并运行我们的示例场景。尝试使用 [email protected]/user2 登录并访问 所有事件 页面。您将看到仅列出生日事件。当使用 [email protected]/admin1 登录并查看 所有事件 页面时,不会显示任何事件。但是,如果我们直接导航到一个事件,它就不会受到保护。你能根据你在本章中学到的知识弄清楚如何保护对事件的直接访问吗?

如果您还没有弄清楚,您可以通过对 CalendarService 进行以下更新来确保直接访问事件,如下所示:

    src/main/java/com/packtpub/springsecurity/service/CalendarService.java
    @PostAuthorize("hasPermission(filterObject, 'read') " +
    "or hasPermission(filterObject, 'admin_read')")
    Event getEvent(int eventId);

我们现在有了基于 ACL 的安全性的基本工作设置(尽管是一个非常简单的场景)。让我们继续对我们在本演练中看到的概念进行更多解释,然后回顾典型 Spring ACL 实现中的几个注意事项,您应该在使用它之前考虑这些注意事项。

Your code should look like chapter12.01-calendar.

值得注意的是,我们在创建事件时并没有创建新的 ACL 条目。因此,在当前状态下,如果您创建一个事件,您将收到类似于以下的错误:

Spring Security 应用程序执行期间出现异常!找不到对象身份 org.springframework.security.acls.domain.ObjectIdentityImpl [类型:com.packtpub.springsecurity.domain.Event;标识符:103].

高级 ACL 主题

我们在配置 ACL 环境期间略过的一些高级主题与 ACE 权限以及使用 GrantedAuthority 指示符来协助 ACL 环境确定某些类型的运行时是否更改为允许使用 ACL。现在我们有了一个工作环境,我们将回顾这些更高级的主题。

权限如何工作

权限不过是由整数中的位表示的单个逻辑标识符。访问控制条目根据位掩码授予 SIDs 权限,该位掩码包括适用于该访问控制条目的所有权限的逻辑与。

默认权限实现 o.s.s.acls.domain.BasePermission 定义了一系列表示常见 ACL 授权动词的整数值。这些整数值对应于整数中设置的单个位,因此 BasePermission 的值,WRITE,整数值 1 的按位值为212

如下图所示:

读书笔记《spring-security-third-edition》访问控制列表

我们可以看到,由于 Read 和 Write 的应用,Sample 权限位掩码的整数值为 3 权限值的权限。上图中显示的所有标准整数单一权限值都在 BasePermission 对象中定义为静态常量。

BasePermission 中包含的逻辑常量只是 ACE 中常用权限的合理基线,在 Spring Security 框架内没有语义意义。对于非常复杂的 ACL 实现来说,发明他们自己的自定义权限是很常见的,用与领域或业务相关的最佳实践示例来扩充最佳实践示例。

一个经常让用户感到困惑的问题是位掩码在实践中的使用方式,因为许多数据库要么不支持按位逻辑,要么不以可扩展的方式支持它。 Spring ACL 打算通过将计算与位掩码相关的适当权限的更多负载放在应用程序而不是数据库上来解决这个问题。

回顾解析过程很重要,我们可以看到 AclPermissionEvaluator 如何将在方法本身上声明的权限(在我们的示例中,使用 @PostFilter 注释)解析为真正的 ACL 权限。

下图说明了 Spring ACL 执行的针对请求主体的相关 ACE 评估声明的权限的过程:

读书笔记《spring-security-third-edition》访问控制列表

我们看到 AclPermissionEvaluator 依赖于实现两个接口 o.s.s.acls.model.ObjectIdentityRetrievalStrategyo.s.s.acls.model.SidRetrievalStrategy 的类来检索 ObjectIdentitySIDs 适用于授权检查。关于这些策略需要注意的重要一点是,默认实现类如何根据授权检查的上下文实际确定要返回的 ObjectIdentitySIDs 对象。

ObjectIdentity 对象有两个属性,typeidentifier,它们派生自在运行时检查的对象,用于声明 ACE 条目。默认的 ObjectIdentityRetrievalStrategy 接口使用完全限定的类名来填充 type 属性。 identifier 属性填充有签名为 Serializable getId() 的方法的结果,该方法在实际对象实例上调用。

由于您的对象不需要实现与 ACL 检查兼容的接口,因此实现具有特定签名的方法的要求对于实现 Spring Security ACL 的开发人员来说可能是令人惊讶的。提前计划并确保您的域对象包含此方法!您还可以实现自己的 ObjectIdentityRetrievalStrategy 类(或开箱即用实现的子类)来调用您选择的方法。不幸的是,该方法的名称和类型签名是不可配置的。

不幸的是,AclImpl的实际实现直接比较了我们在@PostFilter注解中指定的SpEL表达式中指定的权限,和数据库中存储在ACE上的权限,没有使用位逻辑。 Spring Security 社区正在争论这是无意的还是按预期工作的,但无论如何,在声明具有权限组合的用户时需要小心,因为 AclEntryVoter 必须配置为所有权限组合,或者 ACE 需要忽略权限字段旨在存储多个值,而是为每个 ACE 存储单个权限这一事实。

如果您想用我们的简单场景验证这一点,请将我们授予 [email protected] SID 的 READ 权限更改为 Read Write,转换为 3 的值。这将在 data.sql 文件中更新,如下所示:

    src/main/resources/data.sql
    insert into acl_entry
   (acl_object_identity, ace_order, sid, mask, granting, 
   audit_success, audit_failure) values(30, 1, 20, 3, true, true, true);
您的代码应如下所示 第 12.02 章-日历

自定义 ACL 权限声明

正如前面关于权限声明的讨论中所述,权限只不过是整数位值的逻辑名称。因此,可以扩展 o.s.s.acls.domain.BasePermission 类并声明您自己的权限。我们将在这里介绍一个非常简单的场景,我们在其中创建一个名为 ADMIN_READ 的新 ACL 权限。这是一项仅授予管理用户的权限,并将分配用于保护只​​有管理员才能读取的资源。虽然是 JBCP 日历应用程序的一个人为示例,但这种类型的自定义权限使用经常发生在处理个人身份信息(例如,社会安全号码等)的情况下——回想一下,我们在 第 1 章不安全应用程序剖析)。

让我们通过执行以下步骤开始进行支持此操作所需的更改:

  1. The first step is to extend the BasePermission class with our own com.packtpub.springsecurity.acls.domain.CustomPermission class, as follows:
        package com.packtpub.springsecurity.acls.domain;
        public class CustomPermission extends BasePermission {
           public static final Permission ADMIN_READ = new 
           CustomPermission(1 << 5, 'M'); // 32
           public CustomPermission(int mask, char code) {
               super(mask, code);
           }
        }
  1. Next, we will need to configure the o.s.s.acls.domain.PermissionFactory default implementation, o.s.s.acls.domain.DefaultPermissionFactory, to register our custom permission logical value. The role of PermissionFactory is to resolve permission bitmasks into logical permission values (which can be referenced by the constant value, or by name, such as ADMIN_READ, in other areas of the application). The PermissionFactory instance requires that any custom permission is registered with it for proper lookup. We have included the following configuration that registers our CustomPermission class, as follows:
        src/main/java/com/packtpub/springsecurity/configuration/
        AclConfig.java
        @Bean
        public DefaultPermissionFactory permissionFactory(){
         return new DefaultPermissionFactory(CustomPermission.class);
        }
  1. Next, we will need to override the default PermissionFactory instance for our BasicLookupStrategy and AclPermissionEvaluator interfaces with the customized DefaultPermissionFactory interface. Make the following updates to your security-acl.xml file:
src/main/java/com/packtpub/springsecurity/configuration/AclConfig.java
@Bean
public AclPermissionEvaluator permissionEvaluator(){
   AclPermissionEvaluator pe = new
                               AclPermissionEvaluator(aclService());
   pe.setPermissionFactory(permissionFactory());
   return pe;
}
@Bean
public LookupStrategy lookupStrategy(){
   BasicLookupStrategy ls = new BasicLookupStrategy(
                                       dataSource,
                                       aclCache(),
                                      aclAuthorizationStrategy(),
                                      consoleAuditLogger());
   ls.setPermissionFactory(permissionFactory());
   return ls;
}
  1. We also need to add the SQL query to utilize the new permission to grant access to the conference call (acl_object_identity ID of 31) event to [email protected]. Make the following updates to data.sql:
        src/main/resources/data.sql
        insert into acl_sid (id, principal, sid) values (23, true,   
        '[email protected]');
        insert into acl_entry (acl_object_identity, ace_order, sid, 
        mask, granting, audit_success, audit_failure) 
        values(31, 1, 23, 32, true, true, true);

我们可以看到新的整数位掩码值 32 已在 ACE 数据中被引用。这有意对应于我们在 Java 代码中定义的新 ADMIN_READ ACL 权限。电话会议事件由 ACL_OBJECT_IDENTITY 表中的主键值 31 引用(存储在 object_id_identity 列中)。

  1. The last step is to update our CalendarService's getEvents() method to utilize our new permission, as follows:
        @PostFilter("hasPermission(filterObject, 'read') " + "or    
        hasPermission(filterObject, 'admin_read')")
        List<Event> getEvents();

完成所有这些配置后,我们可以再次启动站点并测试自定义 ACL 权限。根据我们配置的示例数据,当各种可用用户单击类别时会发生以下情况:

用户名/密码

生日派对活动

电话会议活动

其他活动

[email protected]/user2

允许通过 READ

拒绝

拒绝

[email protected]/admin1

拒绝

通过 ADMIN_READ 允许

拒绝

[email protected]/user1

拒绝

拒绝

拒绝

我们可以看到,即使使用我们的简单案例,我们现在也能够以非常有限的方式扩展 Spring ACL 功能,以说明这个细粒度访问控制系统的强大功能。

Your code should look like chapter12.03-calendar.

启用 ACL 权限评估

我们在第 2 章中看到,Spring Security 入门< /em>,Spring Security JSP 标记库提供了向用户公开与身份验证相关的数据并根据各种规则限制用户可以看到的内容的功能。到目前为止,在本书中,我们使用了基于 Spring Security 构建的 Thymeleaf Security 标签库。

同样的标签库也可以直接与启用 ACL 的系统进行交互!通过我们的简单实验,我们围绕首页列表中的前两个类别配置了一个简单的 ACL 授权场景。让我们看一下以下步骤,并了解如何在我们的 Thymeleaf 页面中启用 ACL 权限评估:

  1. First, we will need to remove our @PostFilter annotation from the getEvents() method in our CalendarService interface in order to give our JSP tag library a chance to filter out the events that are not allowed for display. Go ahead and remove @PostFilter now, as follows:
        src/main/java/com/packtpub/springsecurity/service/
        CalendarService.java
        List<Event> getEvents();
  1. Now that we have removed @PostFilter, we can utilize the <sec:authorize-acl> tag to hide the events that the user doesn't actually have access to. Refer to the table in the preceding section as a refresher of the access rules we've configured up to this point!
  2. We'll wrap the display of each event with the <sec:authorize-acl> tag, declaring the list of permissions to check on the object to be displayed:
        src/main/resources/templates/events/list.html
        <tr th:each="event : ${events}" sec:authorize-acl="${event} :: '1,32'">
           <td th:text="${#calendars.format(event.when, 'yyyy-MM-dd HH:mm')}">today</td>
           <td th:text="${event.owner.name}"></td>
           <td th:text="${event.attendee.name}"> </td>
           <td><a th:href="@{'/events/{id}'(id=${event.id})}" th:text="${event.summary}"></a></td>
        </tr>
  1. Think for a moment about what we want to occur here—we want the user to see only the items to which they actually have the READ or ADMIN_READ (our custom permission) access. However, to use the tag library, we need to use the permission mask, which can be referenced from the following table:

姓名

面具

阅读

1

2

ADMIN_READ

32

在幕后,标签实现使用了本章前面讨论过的相同的 SidRetrievalStrategyObjectIdentityRetrievalStrategy 接口。因此,访问检查的计算遵循与启用 ACL 的方法安全性投票相同的工作流程。正如我们稍后将看到的,标签实现也将使用相同的 PermissionEvaluator

我们已经使用引用 DefaultMethodSecurityExpressionHandlerexpressionHandler 元素配置了我们的 GlobalMethodSecurityConfiguration 配置。 DefaultMethodSecurityExpressionHandler 实现知道我们的 AclPermissionEvaluator 接口,但我们还必须让 Spring Security 的 web 层知道 AclPermissionEvalulator。如果您考虑一下,这种对称性是有道理的,因为保护方法和 HTTP 请求正在保护两种截然不同的资源。幸运的是,Spring Security 的抽象使这变得相当简单。

  1. Add a DefaultWebSecurityExpressionHandler handler that references the bean with the ID as permissionEvaluator that we have already defined:
        src/main/java/com/packtpub/springsecurity/configuration/
        AclConfig.java
        @Bean
        public DefaultWebSecurityExpressionHandler webExpressionHandler(){
           return new DefaultWebSecurityExpressionHandler(){{
              setPermissionEvaluator(permissionEvaluator());
          }};
        }
  1. Now, update SecurityConfig.java to refer to our webExpressionHandler implementation, as follows:
        src/main/java/com/packtpub/springsecurity/configuration/
        SecurityConfig.java
        @Autowired
        private DefaultWebSecurityExpressionHandler webExpressionHandler;
        @Override
        protected void configure(HttpSecurity http) throws Exception {
           http.authorizeRequests()
             .expressionHandler(webExpressionHandler);
           ...
        }

您可以看到这些步骤与我们如何将权限处理支持添加到方法安全性非常相似。这一次,它稍微简单了一点,因为我们能够重用 ID 为我们已经配置的 PermissionEvaluator 的同一个 bean。

启动我们的应用程序并尝试以不同的用户身份访问 All Events 页面。您会发现现在使用我们的标签库而不是 @PostFilter 注释来隐藏用户不允许的事件。我们仍然知道直接访问事件将允许用户看到它。但是,通过将您在本章中学到的内容与您在本章中学到的关于 @PostAuthorize 注释的内容相结合,可以轻松添加这一点。

Your code should look like chapter12.04-calendar.

可变 ACL 和授权

尽管 JBCP 日历应用程序没有实现完整的用户管理功能,但您的应用程序很可能具有通用功能,例如新用户注册和管理用户维护。到目前为止,缺少这些特性——我们在应用程序启动时使用 SQL 插入来解决这些特性——并没有阻止我们展示 Spring Security 和 Spring ACL 的许多特性。

但是,正确处理已声明 ACL 的运行时更改,或者系统中用户的添加或删除,对于维护基于 ACL 的授权环境的一致性和安全性至关重要。 Spring ACL 通过可变 ACL (o.s.s.acls.model.MutableAcl) 的概念解决了这个问题。

MutableAcl 接口扩展了标准 ACL 接口,允许对 ACL 字段进行运行时操作,以更改特定 ACL 的内存表示。此附加功能包括创建、更新或删除 ACE、更改 ACL 所有权和其他有用功能的能力。

那么,我们可能期望 Spring ACL 模块开箱即用,提供一种将运行时 ACL 更改持久保存到 JDBC 数据存储区的方法,而且确实如此。 o.s.s.acls.jdbc.JdbcMutableAclService 类可用于创建、更新和删除数据库中的 MutableAcl 实例,以及对其他支持进行一般维护ACL 的表(处理 SIDsObjectIdentity 和域对象类名称)。

回想一下本章前面的内容,AclAuthorizationStrategyImpl 类允许我们为可变 ACL 上的操作指定管理角色。这些作为 bean 配置的一部分提供给构造函数。构造函数参数及其含义如下:

Arg #

它有什么作用?

1

指示主体需要具有的权限才能在运行时获得受 ACL 保护的对象的所有权

2

指示主体需要具有的权限才能在运行时更改受 ACL 保护的对象的审计

3

指示主体需要具有的权限才能在运行时对受 ACL 保护的对象进行任何其他类型的更改(创建、更新和删除)

当列出三个参数时,我们只指定了一个构造函数参数,这可能会让人感到困惑。 AclAuthorizationStrategyImpl 类还可以接受单个 GrantedAuthority,然后将其用于所有三个参数。如果我们希望所有操作都使用相同的 GrantedAuthority,这很方便。

JdbcMutableAclService 接口包含许多用于在运行时操作 ACL 和 ACE 数据的方法。虽然这些方法本身是相当容易理解的(createAclupdateAcldeleteAcl),但配置和使用 JdbcMutableAclService 通常也很难。

让我们修改 CalendarService 来为新创建的事件创建一个新的 ACL。

将 ACL 添加到新创建的事件

目前,如果用户创建了一个新事件,它在 All Events 视图中对用户是不可见的,因为我们使用的是 <sec:authorize- acl> 标记仅显示用户有权访问的事件对象。让我们更新我们的 DefaultCalendarService 接口,以便当用户创建新事件时,他们被授予对该事件的读取访问权限,并将在 所有事件< /span> 页面。

让我们看一下将 ACL 添加到新创建的事件的以下步骤:

  1. The first step is to update our constructor to accept MutableAclService and UserContext:
        src/main/java/com/packtpub/springsecurity/service/
        DefaultCalendarService.java
        public class DefaultCalendarService implements CalendarService {
           ...
           private final MutableAclService aclService;
           private final UserContext userContext;
            @Autowired
            public DefaultCalendarService(EventDao eventDao,
            CalendarUserDao userDao, CalendarUserRepository userRepository,
            PasswordEncoder passwordEncoder, MutableAclService aclService,
            UserContext userContext) {
                   ...
                  this.aclService = aclService;
                  this.userContext = userContext;
               }
  1. Then, we need to update our createEvent method to also create an ACL for the current user. Make the following changes:
        src/main/java/com/packtpub/springsecurity/service/
        DefaultCalendarService.java
        @Transactional
        public int createEvent(Event event) {
           int result = eventDao.createEvent(event);
           event.setId(result);
           // Add new ACL Entry:
           MutableAcl acl = aclService.createAcl
           (new ObjectIdentityImpl(event));
           PrincipalSid sid = new PrincipalSid(
                    userContext.getCurrentUser().getEmail());
           acl.setOwner(sid);
           acl.insertAce(0, BasePermission.READ, sid, true);
           aclService.updateAcl(acl);
           return result;
        }
  1. The JdbcMutableAclService interface uses the current user as the default owner for the created MutableAcl interface. We chose to explicitly set the owner again to demonstrate how this can be overridden.

  1. We then add a new ACE and save our ACL. That's all there is to it.
  2. Start the application and log in with [email protected]/user1.
  3. Visit the All Events page and see that there are no events currently listed. Then, create a new event and it will be displayed the next time you visit the All Events page. If you log in as any other user, the event will not be visible on the All Events page. However, it will potentially be visible to the user, since we have not applied security to other pages. Again, we encourage you to attempt to secure these pages on your own.
Your code should look like chapter12.05-calendar.

典型 ACL 部署的注意事项

实际上,在真正的业务应用程序中部署 Spring ACL 往往是相当复杂的。我们用大多数 Spring ACL 实现场景中出现的一些注意事项来总结 Spring ACL 的覆盖范围。

ACL 可扩展性和性能建模

对于中小型应用程序,添加 ACL 是相当易于管理的,虽然它增加了数据库存储和运行时性能的开销,但影响不大。但是,根据 ACL 和 ACE 建模的粒度,中型到大型应用程序中的数据库行数可能会非常惊人,即使是最有经验的数据库管理员也能完成任务。

假设我们要扩展 ACL 以涵盖 JBCP 日历应用程序的扩展版本。假设用户可以管理帐户、将图片发布到事件以及从事件中管理(添加/删除用户)。我们将数据建模如下:

  • All users have accounts.
  • 10% of users are able to administer an event. The average number of events that a user can administer will be two.
  • Events will be secured (read-only) per customer, but also need to be accessible (read/write) by administrators.
  • 10 percent of all customers will be allowed to post pictures. The average number of posts per user will be 20.
  • Posted pictures will be secured (read-write) per user, as well as administrators. Posted pictures will be read-only for all other users.

鉴于我们对 ACL 系统的了解,我们知道数据库表具有以下可伸缩性属性:

表格

随数据扩展

可扩展性说明

ACL_CLASS

每个域类需要一行。

ACL_SID

是(用户)

每个角色需要一行 (GrantedAuthority)。每个用户帐户都需要一行(如果每个用户都保护了各个域对象)。

ACL_OBJECT_IDENTITY

是(每个类的域类实例)

每个安全域对象实例需要一行。

ACL_ENTRY

是(域对象实例单个 ACE 条目)

每个 ACE 需要一行;单个域对象可能需要多行。

我们可以看到 ACL_CLASS 并没有真正的可扩展性问题(大多数系统的域类少于 1,000 个)。 ACL_SID 表将根据系统中的用户数量线性扩展。这可能不是问题,因为其他与用户相关的表也会以这种方式扩展(用户帐户等)。

关注的两个表是 ACL_OBJECT_IDENTITYACL_ENTRY。如果我们对为单个客户的订单建模所需的估计行进行建模,我们会得出以下估计:

表格

每个事件的 ACL 数据

每张图片帖子的 ACL 数据

ACL_OBJECT_IDENTITY

单个事件需要一行。

一个帖子需要一行。

ACL_ENTRY

三行 - 所有者(用户 SID)读取访问需要一行,管理组 SID< 需要两行(读取访问权限,写入访问权限) /kbd>。

四行 — 用户组 SID 读取访问需要一行,所有者需要写入访问一行,管理组 SID 需要两行(与事件一样)

然后,我们可以从上一页中获取使用假设,并计算以下 ACL 可伸缩性矩阵,如下所示:

表格/对象

比例因子

估计(低)

估计(高)

用户

10,000

1,000,000

事件

# 用户数 * 0.1 * 2

2,000

200,000

图片贴

# 用户数 * 0.1 * 20

20,000

2,000,000

ACL_SID

# 用户

10,000

1,000,000

ACL_OBJECT_IDENTITY

# 事件 + # 图片帖子

220,000

2,200,000

ACL_ENTRY

(#Events * 3) + (# Picture Posts * 4)

86,000

8,600,000

从这些仅基于典型 ACL 实现中可能涉及和保护的业务对象子集的预测中,您可以看到专门用于存储 ACL 信息的数据库行数可能会线性增长(或更快)您的实际业务数据。尤其是在大型系统规划中,预测您可能使用的 ACL 数据量极为重要。非常复杂的系统拥有数亿行与 ACL 存储相关的情况并不少见。

不要打折定制开发成本

使用 Spring ACL-secured 环境通常需要大量的开发工作,超出我们到目前为止描述的配置步骤。我们的示例配置场景有以下限制:

  • No facility is provided for responding to the manipulation modification of events or modification of permissions
  • Not all of the application is using permissions. For example, the My Events page and directly navigating to an event are both not secured

该应用程序没有有效地使用 ACL 层次结构。如果我们将 ACL 安全性推广到整个站点,这些限制将显着影响功能。这就是为什么在计划跨应用程序的 Spring ACL 部署时至关重要的原因,您必须仔细检查域数据被操作的所有位置,并确保这些位置正确更新 ACL 和 ACE 规则,并使缓存无效。通常,方法和数据的保护发生在服务或业务应用程序层,维护 ACL 和 ACE 所需的挂钩发生在数据访问层。

读书笔记《spring-security-third-edition》访问控制列表

如果您正在处理一个相当标准的应用程序架构,并且对功能进行了适当的隔离和封装,那么很可能存在一个易于识别的用于这些更改的中心位置。另一方面,如果您要处理的架构已经下放(或者从一开始就没有设计好),那么在数据操作代码中添加 ACL 功能和支持挂钩可能会非常困难。

正如前面所暗示的,重要的是要记住,自 Acegi 1.x 时代以来,Spring ACL 架构并没有发生显着变化。在那段时间里,许多用户试图实现它,并记录并记录了几个重要的限制,其中许多被捕获在 Spring Security JIRA 存储库中 (http://jira.springframework.org/)。问题 SEC-479 是一些关键限制的有用入口点,其中许多限制在 Spring Security 3 中仍未解决,并且(如果它们适用于您的情况)可能需要大量自定义编码才能解决问题。

以下是一些最重要和最常遇到的问题:

  • The ACL infrastructure requires a numeric primary key. For applications that use a GUID or UUID primary key (which occurs more frequently due to more efficient support in modern databases), this can be a significant limitation.
  • At the time of writing this, the JIRA issue, SEC-1140, documents the issue that the default ACL implementation does not correctly compare permission bitmasks using bitwise operators. We covered this earlier in the section on permissions.
  • Several inconsistencies exist between the method of configuring Spring ACL and the rest of Spring Security. In general, it is likely that you will run into areas where class delegates or properties are not exposed through DI, necessitating an override and rewrite strategy that can be time consuming and expensive to maintain.
  • The permission bitmask is implemented as an integer, and thus has 32 possible bits. It's somewhat common to expand the default bit assignments to indicate permissions on individual object properties (for example, assigning a bit to read the social security number of an employee). Complex deployments may have well over 32 properties per domain object, in which case the only alternative would be to remodel your domain objects around this limitation.

根据您的特定应用程序的要求,您可能会遇到其他问题,尤其是在实施某些类型的自定义时需要更改的类的数量。

我应该使用 Spring Security ACL 吗?

就像整个应用 Spring Security 的细节高度依赖于业务一样,Spring ACL 支持的应用也是如此。事实上,由于 ACL 支持与业务方法和域对象的紧密耦合,这往往更是如此。我们希望本 Spring ACL 指南解释了分析 Spring ACL 以在您的应用程序中使用所需的重要的高级和低级配置和概念,并可以帮助您确定其功能并将其与实际使用相匹配。

概括

在本章中,我们重点介绍了基于 ACL 的安全性以及 Spring ACL 模块如何实现此类安全性的具体细节。

我们回顾了 ACL 的基本概念,以及为什么它们可以非常有效地解决授权的许多原因。此外,您还学习了与 Spring ACL 实现相关的关键概念,包括 ACE、SID 和对象标识。我们检查了支持分层 ACL 系统所需的数据库模式和逻辑设计。我们配置了所有必需的 Spring bean 以启用 Spring ACL 模块,并增强了其中一个服务接口以使用带注释的方法授权。然后,我们将数据库中的现有用户和站点本身使用的业务对象绑定到一组 ACE 声明和支持数据的样本中。我们回顾了 Spring ACL 权限处理的概念。我们扩展了对 Spring Security Thymeleaf 标记库和 SpEL 表达式语言(用于方法安全)的了解,以利用 ACL 检查。我们讨论了可变 ACL 概念并回顾了可变 ACL 环境中所需的基本配置和自定义编码。我们开发了一个自定义 ACL 权限并配置了应用程序以展示其有效性。我们配置并分析了 Ehcache 缓存管理器的使用,以减少 Spring ACL 对数据库的影响。我们分析了在复杂的业务应用程序中使用 Spring ACL 系统的影响和设计注意事项。

这结束了我们关于 Spring Security ACL 的讨论。在下一章中,我们将深入探讨 Spring Security 的工作原理。