Spring Security 3.0.0.M1 发布

工程 | Luke Taylor | 2009年6月3日 | ...

我们很高兴地宣布 Spring Security 3.0 的第一个里程碑版本现已提供 下载。该版本也可通过 Maven 里程碑存储库获取:http://maven.springframework.org/milestone。与 Spring 3.0 一样,这是第一个需要最低 JDK 1.5 才能运行的版本,并且还需要 Spring 3.0,因此如果您尚未使用它,则应获取 Spring 3.0.0.M3 版本。那么这个版本有哪些新功能和变化呢?

基于表达式的访问控制

此版本首次包含我们 Spring-EL 基于授权的支持预览。您现在可以在方法注解和 Web 安全中使用表达式。与熟悉的属性和基于投票者的机制相比,这带来了许多新的可能性。一个简单的示例可能是一个好的开始。以下是一个 Web 应用程序的示例,使用安全命名空间

  <http use-expressions="true">
     <intercept-url pattern="/secure/**" access="hasRole('ROLE_SUPERVISOR') and hasIpAddress('192.168.1.0/24')" />
     ...
  </http>;

内置的hasRole('ROLE_SUPERVISOR')表达式没有什么花哨的 - 它只是检查当前用户的权限列表,如果他们具有给定的角色则返回 true。但是我们添加了一个额外的表达式来指定发出请求的 IP 地址必须在由子网/掩码参数定义的范围内。这在实际使用中是否实用取决于您的网络设置,但它说明了基于表达式的方案的强大功能。以前包含在“access” XML 属性中的安全属性列表已被布尔表达式替换。如果它计算结果为“true”,则授予访问权限。如果它计算结果为“false”,则拒绝访问。

@Pre 和 @Post 注解

方法安全比我们刚刚看到的 Web 请求的简单允许或拒绝更复杂。为了更全面地支持在方法安全中使用表达式,我们引入了四个新的注解,它们可以包含在方法调用前后应用的表达式属性。要启用对它们的 支持,在global-method-security命名空间元素上有一个新的属性

    <global-method-security pre-post-annotations="enabled"/>

最明显的有用注解是@PreAuthorize它控制方法是否可以实际调用。例如(来自“Contacts”示例应用程序)


    @PreAuthorize("hasRole('ROLE_USER')")
    public void create(Contact contact);

这意味着只有具有“ROLE_USER”角色的用户才能被允许访问。这里没有新东西。但是关于

  
    @PreAuthorize("hasPermission(#contact, 'admin')")
    public void deletePermission(Contact contact, Sid recipient, Permission permission);

这里我们实际上使用方法参数作为表达式的一部分来确定当前用户是否对给定的联系人具有“admin”权限。该hasPermission()表达式通过应用程序上下文链接到 Spring Security ACL 模块(有关如何实现此功能,请参阅 Contacts 示例配置)。您可以通过名称访问任何方法参数作为表达式变量,前提是您的代码已编译了调试信息。任何 Spring-EL 功能都可以在表达式中使用,因此您还可以访问参数上的属性。例如,如果您希望特定方法仅允许用户名与联系人用户名匹配的用户访问,您可以编写


    @PreAuthorize("#contact.name == principal.name)")
    public void doSomething(Contact contact);

在这里,我们访问另一个内置表达式,它是当前 Spring Security 的“principal”Authentication从安全上下文中获取的对象。您还可以使用表达式名称“authentication”直接访问Authentication对象本身。授权也可以在方法调用完成后执行,使用@PostAuthorize注解。要访问方法的返回值,请在表达式中使用内置名称“returnObject”。

过滤

您可能已经知道,Spring Security 还支持对集合和数组进行过滤,这现在可以使用表达式来实现。这最常在方法的返回值上执行。例如
    
    @PreAuthorize("hasRole('ROLE_USER')")
    @PostFilter("hasPermission(filterObject, 'read') or hasPermission(filterObject, 'admin')")
    public List getAll();

@PostFilter注解一起使用时,Spring Security 会遍历返回的集合,并删除提供的表达式为 false 的任何元素。名称“filterObject”指的是集合中的当前对象。您还可以使用方法调用之前进行过滤,使用@PreFilter,尽管这可能是一个不太常见的要求。语法完全相同,但如果有多个参数是集合类型,则必须使用此注解的“filterTarget”属性按名称选择一个。

代码库重构

在 3.0 之前的版本中,Spring Security 的大部分代码都包含在spring-security-corejar 中。多年来,随着添加了更多功能,跟踪代码库本身以及第三方库的依赖关系变得更加困难。例如,对于用户来说,很难确定核心 Maven pom.xml 中列出的依赖项中的哪一项是框架内特定功能集所需的。此外,原始的包结构和类名自 2003 年框架起源于 Acegi Security 以来就一直存在,当时只支持一些基本的认证机制。随着代码量的增加和功能集的扩展,这种包结构开始显露出它的年龄。
Spring Security 2.0.4 Package Structure

Spring Security 2.0.4 包结构

上图显示了 2.0.4 版本中核心、核心-tiger、cas-client 和 acl jar 的高级包图,由 Structure101 生成。您不必成为代码结构专家就能意识到这里存在一些问题。存在大量循环引用,并且包内没有清晰的整体依赖关系结构。还有一些问题是包跨越 jar 边界拆分,这可能会导致 OSGi 出现问题。代码结构中的这种脆弱性可能会随着 Spring Security 的发展而导致维护开销,因此决定在 3.0 版本中重构代码,为将来的开发提供稳定的基础。让我们看看现在如何组织这些内容。

项目 Jar 包

我们首先做的是将核心拆分为多个 jar 包。该spring-security-corejar 现在仅包含基本的认证和访问控制代码,并且更加简洁。例如,它不依赖于 LDAP 或 servlet API,并且现在有单独的 jar 包用于特定于 Web 的代码和 LDAP。我们还将命名空间解析代码拆分到一个单独的 jar 包中,因为它依赖于大多数其他 jar 包,并且不公开您可能在应用程序中直接使用的任何公共 API。只有在应用程序上下文 XML 文件中使用 Spring Security 命名空间配置时,才需要使用它。主要的项目 jar 包如下表所示。
Jar 包名称 描述 何时使用 根包
spring-security-core 核心认证和访问控制类和接口。远程支持和基本配置 API。 任何使用 Spring Security 的应用程序都需要。支持独立应用程序、远程客户端、方法(服务层)安全和 JDBC 用户配置。 org.springframework.security.core, org.springframework.security.access, org.springframework.security.authentication, org.springframework.security.provisioning, org.springframework.security.remoting
spring-security-web 过滤器和其他 Web 安全基础设施以及相关代码。任何具有 servlet API 依赖项的内容。 如果您需要 Spring Security Web 认证服务和基于 URL 的访问控制 org.springframework.security.web
spring-security-config 命名空间解析代码。 如果您正在使用 Spring Security XML 命名空间。 org.springframework.security.config
spring-security-ldap LDAP 认证和配置代码。 如果您需要使用 LDAP 认证或管理 LDAP 用户条目。 org.springframework.security.ldap
spring-security-acl 域对象 ACL 实现。 如果您需要对应用程序中的特定域对象实例应用安全。 org.springframework.security.acls
spring-security-cas-client Spring Security 的 CAS 客户端集成。 如果您想将 Spring Security Web 认证与 CAS 单点登录服务器一起使用。 org.springframework.security.cas
spring-security-openid OpenID Web 认证支持。 如果您需要针对外部 OpenID 服务器对用户进行身份验证。 org.springframework.security.openid
现在在 jar 包级别有了更清晰的关注点分离。例如,如果您正在编写 Web 应用程序,则只需要 Web jar 包(及其传递依赖项)。这也使代码更易于导航和理解。Spring Security 3.0 jar 包之间的依赖关系现在构成了我们上面查看的 2.0.4 版本的相同代码集,如下所示
Spring Security 3.0 jars

Spring Security 3.0.0.M1 Jar 包依赖关系

包结构

这些 jar 包的包布局如下所示。如您所见,不再有任何循环引用,结构也更加清晰。
Spring Security 3.0.0.M1 Package Structure

Spring Security 3.0.0.M1 包结构

core 包和子包包含在整个框架中使用的基本类和接口,以及核心 jar 中的其他两个主要包是 authenticationaccess。该 access 包包含访问控制/授权代码,例如 AccessDecisionManager 和相关的基于投票者的实现、拦截和方法安全基础设施、注解类以及对 Spring Security 3.0 基于表达式的访问控制的支持。该 authentication 包包含 AuthenticationManager 和相关类(例如认证异常类)、简单的基于 DAO 的认证提供程序和密码编码器。

其他杂项更改

重命名的类

代码库中的一些类名也开始显示它们的年龄。例如,AbstractProcessingFilter现在是AbstractAuthenticationProcessingFilter,其最常见的具体子类AuthenticationProcessingFilter现在是UsernamePasswordAuthenticationProcessingFilter,因为框架中现在有很多过滤器处理认证请求。其对应的AuthenticationEntryPoint现在是LoginUrlAuthenticationEntryPoint。名称晦涩的ObjectDefinitionSource已重命名为SecurityMetadataSource,以及AbstractSecurityInterceptor上的相应属性也进行了类似的重命名。实现类和子接口也进行了类似的重命名。HttpSessionContextIntegrationFilter现在是SecurityContextPersistenceFilter并且具有可插拔的策略来控制它如何存储安全上下文 - 它不必存储在HttpSession.

认证成功或失败后的重定向/转发

另一个问题是AbstractProcessingFilter控制浏览器在成功或失败的认证后重定向到的目的地的不同方式的数量。使用了属性和策略的混合。在 Spring Security 3.0.0.M1 中,这些已被两种单独的策略取代AuthenticationSuccessHandlerAuthenticationFailureHandler

它们完全负责处理目标。查看这些接口的Javadoc,并查看问题SEC-745以获取更多信息。

参考手册和网站更新

显然,3.0 参考手册仍在开发中 :-), 但我们一直在进行一些更新。命名空间技术概述 章节应该可以提供框架的合理概述。请随时通过问题跟踪器提交任何想法或补丁。同样,如果您发现任何错误,当然也可以。

项目网站也已更新。常见问题解答 中有一些新问题,并且有一个新页面包含指向演示文稿视频和在线文章的链接。请查看并告知我们您希望在那里看到什么内容(一个外部安全链接页面已经在开发中)。

结论

Spring Security 3 仍有很多工作要做,但我们希望您能尝试此里程碑版本并提供有关新表达式语言支持的一些反馈。您可以在Jira 变更日志中找到迄今为止所有更改的完整列表,您还可以在那里找到指向当前项目路线图的链接。

社区论坛 是询问有关使用 Spring Security 的问题或开始讨论新功能的最佳场所。或者,如果您发现任何问题,可以提出Jira 问题

我们希望您喜欢使用Spring Security

获取 Spring 新闻通讯

与 Spring 新闻通讯保持联系

订阅