spring security5

版本号:5.0.x 参考手册 【翻译自官方GIT - 2018.06.12】

Spring Security参考手册

Spring Security是一个强大且高度可定制的身份验证和访问控制框架。 这是保护基于Spring的应用程序的事实标准。

前言

Spring Security为基于Java EE的企业软件应用程序提供了全面的安全解决方案。 正如您在参考指南中发现的那样,我们试图为您提供一个有用且高度可配置的安全系统。

安全是一个不断变化的目标,追求全面的系统范围方法非常重要。 在安全圈中,我们鼓励您采用"layers of security",以便每个图层都尽可能保证安全,连续图层提供更高的安全性。 每个图层的"tighter"安全性,您的应用程序将更加健壮和安全。 在底层,您需要处理诸如传输安全和系统识别等问题,以缓解中间人攻击。 接下来,您通常会使用防火墙,可能是VPN或IP安全性,以确保只有经过授权的系统才能尝试连接。 在企业环境中,您可以部署一个DMZ,将面向公众的服务器与后端数据库和应用程序服务器分开。 您的操作系统也将扮演重要角色,解决诸如以无特权用户身份运行进程等问题并最大限度提高文件系统安全性。 操作系统通常也会配置自己的防火墙。 希望在这个过程中你会试图阻止对系统的拒绝服务和暴力攻击。 入侵检测系统对于监视和响应攻击也特别有用,因为这些系统能够采取保护措施,例如实时阻止侵入TCP / IP地址。 转移到更高层,您的Java虚拟机将有望配置为最大限度地减少授予不同Java类型的权限,然后您的应用程序将添加自己的问题特定于域的安全配置。 Spring Security使后面的这个领域 - 应用程序的安全性更容易。

当然,您需要正确处理上面提到的所有安全层,以及包含每个层的管理因素。 这些管理因素的非详尽清单将包括安全公告监控,修补,人员审查,审计,变更控制,工程管理系统,数据备份,灾难恢复,性能基准测试,负载监控,集中式日志记录,事件响应程序等。

由于Spring Security专注于帮助企业应用程序安全层,因此您会发现有多少不同的需求与业务问题域相同。 银行应用程序对电子商务应用程序有不同的需求。 电子商务应用程序对企业销售人员自动化工具有不同的需求。 这些自定义要求使应用程序安全性变得有趣,富有挑战性和有益。

请首先阅读入门。 这将向您介绍框架和基于命名空间的配置系统,您可以使用该系统快速启动和运行。 为了更好地理解Spring Security的工作原理以及您可能需要使用的某些类,请阅读体系结构和实现。 本指南的其余部分采用更传统的参考样式,旨在根据需要进行阅读。 我们还建议您尽可能多地阅读应用程序安全问题。 Spring Security不是解决所有安全问题的万能药。 从一开始,应用程序的设计就要考虑到安全性,这一点很重要。 试图改造它并不是一个好主意。 特别是,如果您正在构建Web应用程序,则应该意识到许多潜在的漏洞,例如跨站脚本,请求伪造和会话劫持,您应该从一开始就考虑这些漏洞。 OWASP网站(http://www.owasp.org/)维护着十大Web应用程序漏洞列表以及大量有用的参考信息。

我们希望您发现此参考指南很有用,我们欢迎您的反馈和suggestions

最后,欢迎来到Spring Security community

入门

本指南的后面部分提供了关于框架体系结构和实现类的深入讨论,您需要了解是否需要进行任何严格的自定义。 在这一部分中,我们将介绍Spring Security 4。 0,简要介绍一下该项目的历史,并对如何开始使用该框架稍微考虑一下。 特别是,我们将看看命名空间配置,与传统的Spring bean方法相比,它提供了一种更简单的保护应用程序的方法,您必须单独连接所有实现类。

我们还将看看可用的示例应用程序。 在阅读后面的章节之前,尝试运行这些内容并尝试一下这些内容 - 随着对框架理解的增加,您可以深入了解它们。 请同时查看http:// spring。 io / spring-security [项目网站],因为它有关于构建项目的有用信息,以及指向文章,视频和教程的链接。

介绍

什么是Spring Security?

Spring Security为基于Java EE的企业软件应用程序提供全面的安全服务。 特别强调支持使用Spring Framework构建的项目,Spring Framework是用于企业软件开发的领先Java EE解决方案。 如果您没有使用Spring开发企业应用程序,我们热烈鼓励您仔细研究它。 对Spring的一些熟悉 - 特别是依赖注入原则 - 将帮助您更轻松地熟悉Spring Security。

人们使用Spring Security的原因有很多,但大多数人在找到Java EE的Servlet规范或EJB规范的安全特性后,都没有深入了解典型企业应用场景所需的深度。 在提到这些标准的同时,重要的是要认识到它们在WAR或EAR级别不可移植。 因此,如果切换服务器环境,在新的目标环境中重新配置应用程序的安全性通常需要很多工作。 使用Spring Security克服了这些问题,并且还为您带来了许多其他有用的,可自定义的安全功能。

您可能知道应用程序安全性的两个主要方面是"authentication"和"authorization"(或"access-control")。 这是Spring Security的两大主要领域。 "Authentication"是建立委托人的过程是他们声称的("principal"通常是指可以在您的应用程序中执行操作的用户,设备或其他系统)。 "Authorization"指的是决定是否允许委托人在您的应用程序内执行操作的过程。 为了达到需要授权决定的地步,委托人的身份已经由认证过程确定。 这些概念很常见,并不完全针对Spring Security。

在认证级别,Spring Security支持多种认证模式。 这些认证模式大多由第三方提供,或者由相关标准组织(如互联网工程任务组)开发。 另外,Spring Security还提供了自己的一套认证功能。 具体而言,Spring Security目前支持与所有这些技术的认证集成:

  • HTTP BASIC验证头(基于IETF RFC的标准)

  • HTTP摘要式身份验证标头(基于IETF RFC的标准)

  • HTTP X.509客户端证书交换(基于IETF RFC的标准)

  • LDAP(跨平台认证需求的一种非常常见的方法,特别是在大型环境中)

  • 基于表单的身份验证(用于简单的用户界面需求)

  • OpenID身份验证

  • 基于预先建立的请求标头的认证(例如Computer Associates Siteminder)

  • Jasig中心身份验证服务(也称为CAS,它是一种流行的开源单点登录系统)

  • 远程方法调用(RMI)和HttpInvoker(Spring远程协议)的透明认证上下文传播

  • 自动"remember-me"身份验证(因此您可以勾选一个方框以避免在预定时间段内进行重新身份验证)

  • 匿名身份验证(允许每个未经身份验证的呼叫自动采用特定的安全身份)

  • 运行身份验证(如果一次调用应该使用不同的安全身份进行身份验证,这很有用)

  • Java认证和授权服务(JAAS)

  • Java EE容器认证(如果需要,您仍可以使用容器管理认证)

  • 的Kerberos

  • Java开源单一登录(JOSSO)*

  • OpenNMS网络管理平台*

  • AppFuse *

  • AndroMDA *

  • Mule ESB *

  • 直接Web请求(DWR)*

  • Grails *

  • 挂毯*

  • JTrac *

  • Jasypt *

  • 滚筒*

  • 弹性路径*

  • Atlassian人群*

  • 您自己的身份验证系统(请参阅下文)

(*表示由第三方提供)

许多独立软件供应商(ISV)都采用Spring Security,因为这种灵活的身份验证模型的选择非常重要。 这样做可以让他们快速地将他们的解决方案与他们最终客户需要的任何内容集成起来,而无需进行大量工程或要求客户改变其环境。 如果上述认证机制都不符合您的需求,Spring Security是一个开放平台,编写您自己的认证机制非常简单。 Spring Security的许多企业用户需要与不符合任何特定安全标准的"legacy"系统进行集成,而且Spring Security很高兴能够使用此类系统"play nicely"。

无论身份验证机制如何,Spring Security都提供了一套深层次的授权功能。 有三个主要的感兴趣领域:授权Web请求,授权是否可以调用方法并授权访问单个域对象实例。 为帮助您理解这些差异,请分别考虑Servlet规范Web模式安全性,EJB容器托管安全性和文件系统安全性中的授权功能。 Spring Security在所有这些重要领域提供了深入的功能,我们将在本参考指南的后面部分探讨这些功能。

历史

Spring Security于2003年末开始以"The Acegi Security System for Spring"开始。 Spring Developers的邮件列表上提出了一个问题,询问是否对基于Spring的安全实现给予了任何考虑。 当时Spring社区相对较小(特别是与今天的规模相比),而Spring的确只是从2003年初开始的SourceForge项目。 对这个问题的回应是,这是一个值得的领域,尽管目前缺乏时间阻碍了它的探索。

考虑到这一点,构建了一个简单的安全实现,而不是发布。 几个星期后,Spring社区的另一位成员询问了安全问题,并在当时向他们提供了这些代码。 接下来还有其他几个要求,到2004年1月,大约有20个人在使用这些代码。 这些先锋用户与其他人一起提出了一个建议SourceForge项目是有序的,该项目于2004年3月正式成立。

在那些早期,该项目没有任何自己的认证模块。 集装箱安全管理被用于认证过程,而Acegi Security则专注于授权。 这在一开始就很合适,但随着越来越多的用户请求额外的容器支持,容器特定身份验证领域接口的基本限制变得清晰起来。 还有一个相关的问题,即向容器的类路径添加新的JAR,这是最终用户混淆和错误配置的常见原因。

随后引入了Acegi安全特定的认证服务。 大约一年后,Acegi Security成为Spring Framework的正式子项目。 1。 0. 2006年5月发布了0最终版,经过两年半的积极应用于众多生产软件项目以及数百项改进和社区贡献。

Acegi Security于2007年底成为春季投资组合项目的官方项目,并更名为"Spring Security"。

今天,Spring Security拥有一个强大且活跃的开源社区。 在支持论坛上有数千条关于Spring Security的消息。 有一个积极的核心开发人员从事代码本身的工作,同时也是一个活跃的社区,他们也经常分享补丁和支持他们的同行。

发布编号

了解Spring Security发行版的工作原理非常有用,因为它可以帮助您确定迁移到项目未来版本所涉及的工作(或缺乏)。 每个版本使用一个标准的整数三元组:MAJOR.MINOR.PATCH。 目的是MAJOR版本不兼容,API的大规模升级。 MINOR版本应该在很大程度上保留与旧版次版本的源代码和二进制兼容性,认为可能会有一些设计更改和不兼容的更新。 PATCH级别应该完全兼容,前后颠倒,可能的例外是修改错误和缺陷的更改。

您受到更改影响的程度取决于您的代码的集成程度。 如果您正在进行大量定制,则与使用简单名称空间配置相比,您可能会受到更多的影响。

在推出新版本之前,您应该始终彻底测试您的应用程序。

获得Spring Security

你可以通过几种方式获得Spring Security。 您可以从主http:// spring下载打包发行版。 io / spring-security [Spring Security]页面中,从Maven Central存储库(或Spring Maven存储库中下载快照和里程碑版本)下载各个jar,或者,您可以自己从源代码构建项目。

使用Maven

最小的Spring Security Maven依赖关系集通常如下所示:

pom.xml

         
         
  1. <dependencies>
  2. <!-- ... other dependency elements ... -->
  3. <dependency>
  4. <groupId>org.springframework.security</groupId>
  5. <artifactId>spring-security-web</artifactId>
  6. <version>{spring-security-version}</version>
  7. </dependency>
  8. <dependency>
  9. <groupId>org.springframework.security</groupId>
  10. <artifactId>spring-security-config</artifactId>
  11. <version>{spring-security-version}</version>
  12. </dependency>
  13. </dependencies>

如果您正在使用LDAP,OpenID等附加功能,则还需要包含相应的项目模块

Maven仓库

所有GA版本(即以.RELEASE结尾的版本)都将部署到Maven Central,因此您的POM中不需要声明其他Maven存储库。

如果您使用的是SNAPSHOT版本,则需要确保您已经定义了Spring Snapshot存储库,如下所示:

pom.xml

          
          
  1. <repositories>
  2. <!-- ... possibly other repository elements ... -->
  3. <repository>
  4. <id>spring-snapshot</id>
  5. <name>Spring Snapshot Repository</name>
  6. <url>http://repo.spring.io/snapshot</url>
  7. </repository>
  8. </repositories>

如果您正在使用里程碑或候选版本,则需要确保您已经定义了Spring Milestone存储库,如下所示:

pom.xml

          
          
  1. <repositories>
  2. <!-- ... possibly other repository elements ... -->
  3. <repository>
  4. <id>spring-milestone</id>
  5. <name>Spring Milestone Repository</name>
  6. <url>http://repo.spring.io/milestone</url>
  7. </repository>
  8. </repositories>
Spring框架

Spring Security针对Spring Framework {spring-version}构建,但应该可以在4.0.x中使用。 许多用户会遇到的问题是Spring Security的传递依赖关系解决了可能导致奇怪类路径问题的Spring Framework {spring-version}。

解决这个问题的一个(单调乏味的)方法是将所有Spring Framework模块包含在你的pom的 <dependencyManagement>部分中。 另一种方法是将spring-framework-bom包含在pom.xml<dependencyManagement>部分中,如下所示:

pom.xml

          
          
  1. <dependencyManagement>
  2. <dependencies>
  3. <dependency>
  4. <groupId>org.springframework</groupId>
  5. <artifactId>spring-framework-bom</artifactId>
  6. <version>{spring-version}</version>
  7. <type>pom</type>
  8. <scope>import</scope>
  9. </dependency>
  10. </dependencies>
  11. </dependencyManagement>

这将确保Spring Security的所有传递依赖使用Spring {spring-version}模块。

注意:此方法使用Maven的"bill of materials"(BOM)概念,并且仅在Maven 2.0.9+中提供。 有关如何解决依赖关系的更多详细信息,请参阅 Maven的介绍依赖机制文档

摇篮

最小的Spring Security Gradle依赖关系集通常如下所示:

build.gradle

         
         
  1. dependencies {
  2. compile 'org.springframework.security:spring-security-web:{spring-security-version}'
  3. compile 'org.springframework.security:spring-security-config:{spring-security-version}'
  4. }

如果您正在使用LDAP,OpenID等附加功能,则还需要包含相应的项目模块

Gradle存储库

所有GA版本(即以.RELEASE结尾的版本)都将部署到Maven Central,因此使用mavenCentral()存储库对于GA版本已足够。

build.gradle

          
          
  1. repositories {
  2. mavenCentral()
  3. }

如果您使用的是SNAPSHOT版本,则需要确保您已经定义了Spring Snapshot存储库,如下所示:

build.gradle

          
          
  1. repositories {
  2. maven { url 'https://repo.spring.io/snapshot' }
  3. }

如果您正在使用里程碑或候选版本,则需要确保您已经定义了Spring Milestone存储库,如下所示:

build.gradle

          
          
  1. repositories {
  2. maven { url 'https://repo.spring.io/milestone' }
  3. }
使用Spring 4.0.x和Gradle

默认情况下,Gradle将在解析传递版本时使用最新版本。 这意味着当使用Spring Framework {spring-version}运行Spring Security {spring-security-version}时,通常不需要额外的工作。 但是,有时可能会出现问题,因此最好使用 Gradle的ResolutionStrategy来缓解此问题,如下所示:

build.gradle

          
          
  1. configurations.all {
  2. resolutionStrategy.eachDependency { DependencyResolveDetails details ->
  3. if (details.requested.group == 'org.springframework') {
  4. details.useVersion '{spring-version}'
  5. }
  6. }
  7. }

这将确保Spring Security的所有传递依赖使用Spring {spring-version}模块。

注意:本例使用Gradle 1.9,但可能需要修改才能在将来的Gradle版本中使用,因为这是Gradle中的一项孵化功能。

项目模块

在Spring Security 3.0中,代码库被细分为独立的jar,这些jar更清楚地区分了不同的功能区域和第三方依赖关系。 如果您使用Maven构建项目,那么这些模块将添加到您的pom.xml中。 即使您不使用Maven,我们也建议您参考pom.xml文件以了解第三方依赖关系和版本。 或者,一个好主意是检查示例应用程序中包含的库。

核心 - spring-security-core.jar

包含核心认证和访问控制类和接口,远程处理支持和基本配置API。 由使用Spring Security的任何应用程序所要求。 支持独立应用程序,远程客户端,方法(服务层)安全性和JDBC用户配置。 包含顶级包:

  • org.springframework.security.core

  • org.springframework.security.access

  • org.springframework.security.authentication

  • org.springframework.security.provisioning

远程处理 - spring-security-remoting.jar

提供与Spring Remoting的集成。 除非你正在编写一个使用Spring Remoting的远程客户端,否则你不需要这个。 主包是org.springframework.security.remoting

Web - spring-security-web.jar

包含过滤器和相关的网络安全基础架构代码。 任何具有servlet API依赖性的东西。 如果您需要Spring Security Web认证服务和基于URL的访问控制,您将需要它。 主包是org.springframework.security.web

Config - spring-security-config.jar

包含安全名称空间解析代码和Java配置代码。 如果您使用Spring Security XML名称空间进行配置或Spring Security的Java配置支持,则需要它。 主包是org.springframework.security.config。 这些类别都不能直接用于应用程序。

LDAP - spring-security-ldap.jar

LDAP认证和供应代码。 如果您需要使用LDAP身份验证或管理LDAP用户条目,则为必需。 顶级包装是org.springframework.security.ldap

OAuth 2.0核心 - spring-security-oauth2-core.jar

spring-security-oauth2-core.jar包含为OAuth 2.0授权框架OpenID Connect Core 1.0提供支持的核心类和接口。 这是使用OAuth 2.0OpenID Connect Core 1.0的应用程序所必需的,例如客户端,资源服务器和授权服务器。 顶级包装是org.springframework.security.oauth2.core

OAuth 2.0客户端 - spring-security-oauth2-client.jar

spring-security-oauth2-client.jar是Spring Security对OAuth 2.0授权框架OpenID Connect Core 1.0的客户端支持。 由利用OAuth 2.0 Login和/或OAuth客户端支持的应用程序所需。 顶级包装是org.springframework.security.oauth2.client

OAuth 2.0 JOSE - spring-security-oauth2-jose.jar

spring-security-oauth2-jose.jar包含Spring Security对JOSE(Javascript对象签名和加密)框架的支持。 JOSE框架旨在提供一种安全地在各方之间传输声明的方法。 它由一系列规格构建而成:

  • JSON Web令牌(JWT)

  • JSON Web签名(JWS)

  • JSON Web加密(JWE)

  • JSON Web密钥(JWK)

它包含顶级软件包:

  • org.springframework.security.oauth2.jwt

  • org.springframework.security.oauth2.jose

ACL - spring-security-acl.jar

专门的域对象ACL实现。 用于将安全性应用于应用程序内的特定域对象实例。 顶级包装是org.springframework.security.acls

CAS - spring-security-cas.jar

Spring Security的CAS客户端集成。 如果您想使用CAS单点登录服务器的Spring Security Web认证。 顶级包装是org.springframework.security.cas

OpenID - spring-security-openid.jar

OpenID Web认证支持。 用于对外部OpenID服务器进行身份验证。 org.springframework.security.openid. 需要OpenID4Java。

测试 - spring-security-test.jar

支持使用Spring Security进行测试。

检出来源

由于Spring Security是一个开源项目,我们强烈建议您使用git来检查源代码。 这将使您可以完全访问所有示例应用程序,并且可以轻松构建项目的最新版本。 拥有项目的源代码对于调试也有很大的帮助。 异常堆栈跟踪不再是晦涩难解的黑盒问题,但您可以直接找到导致问题的线路并计算出发生的情况。 源代码是项目的最终文档,通常是查找实际内容的最简单方式。

要获得项目的源代码,请使用以下git命令:

git clone https://github.com/spring-projects/spring-security.git

这将使您可以访问本地计算机上的整个项目历史记录(包括所有版本和分支机构)。

Spring Security 5.1的新增功能

Spring Security 5.1提供了许多新功能。 以下是该版本的亮点。

新功能

  • 测试方法安全性

    • 支持在测试中设置SecurityContext时进行自定义 例如,@WithMockUser(setupBefore = TestExecutionEvent.TEST_EXECUTION)会在JUnit的@Before之后并且在执行测试之前设置一个用户。

    • @WithUserDetails现在可以与ReactiveUserDetailsService一起使用

  • [jackson] - 增加了对BadCredentialsException的支持

  • @ AuthenticationPrincipal

    • 支持在WebFlux中解析bean(已经在Spring MVC中受支持)

    • 支持解决WebFlux中的errorOnInvalidType(已经在Spring MVC中受支持)

样本和指南(从此处开始)

如果您想要开始使用Spring Security,最好的地方就是我们的示例应用程序。

。示例应用程序

来源说明指南

{gh-samples-url} / javaconfig / helloworld [Hello Spring Security]

演示如何将Spring Security与现有的使用基于Java的配置的应用程序集成。

你好春天安全指南

{gh-samples-url} / boot / helloworld [Hello Spring安全启动]

演示如何将Spring Security与现有的Spring Boot应用程序集成。

你好Spring安全启动指南

{gh-samples-url} / xml / helloworld [Hello Spring Security XML]

演示如何将Spring Security与使用基于XML的配置的现有应用程序集成。

Spring Security XML指南

{gh-samples-url} / javaconfig / hellomvc [Hello Spring MVC安全性]

演示如何将Spring Security与现有的Spring MVC应用程序集成。

Spring MVC安全指南

{gh-samples-url} / javaconfig / form [自定义登录表单]

演示如何创建自定义登录表单。

自定义登录表格指南

{gh-samples-url} / boot / oauth2login [OAuth 2.0登录]

演示如何将OAuth 2.0登录与OAuth 2.0或OpenID Connect 1.0 Provider集成。

OAuth 2.0登录指南

Java配置

在Spring 3.1中为Spring Framework添加了对 Java配置的一般支持。 自Spring Security 3.2以来,已经有了Spring Security Java Configuration支持,使用户无需使用任何XML即可轻松配置Spring Security。

如果您熟悉安全名称空间配置,那么您应该会发现它与Security Java Configuration支持之间的相似之处。

注:Spring Security提供了https://github.com/spring-projects/spring-security/tree/master/samples/javaconfig [示例应用程序],演示了如何使用Spring Security Java Configuration。

Hello Web安全Java配置

第一步是创建我们的Spring Security Java配置。 该配置会创建一个名为springSecurityFilterChain的Servlet过滤器,它负责应用程序中的所有安全性(保护应用程序URL,验证提交的用户名和密码,重定向到登录表单等)。 你可以在下面找到Spring Security Java Configuration的最基本的例子:


        
        
  1. import org.springframework.beans.factory.annotation.Autowired;
  2. import org.springframework.context.annotation.*;
  3. import org.springframework.security.config.annotation.authentication.builders.*;
  4. import org.springframework.security.config.annotation.web.configuration.*;
  5. @EnableWebSecurity
  6. public class WebSecurityConfig implements WebMvcConfigurer {
  7. @Bean
  8. public UserDetailsService userDetailsService() throws Exception {
  9. InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
  10. manager.createUser(User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build());
  11. return manager;
  12. }
  13. }

这个配置真的没有太多,但它确实很多。 您可以在下面找到以下功能的摘要:

AbstractSecurityWebApplicationInitializer

下一步是向战争注册{{0}。 这可以在Servlet 3.0+环境中的 Spring的WebApplicationInitializer支持的Java配置中完成。 不出所料,Spring Security提供了一个基类AbstractSecurityWebApplicationInitializer,可确保springSecurityFilterChain为您注册。 我们使用AbstractSecurityWebApplicationInitializer的方式取决于我们是否已经使用Spring,或者Spring Security是我们应用程序中唯一的Spring组件。

不存在Spring的==== AbstractSecurityWebApplicationInitializer

如果您没有使用Spring或Spring MVC,则需要将WebSecurityConfig传递给超类,以确保获取配置。 你可以在下面找到一个例子:


         
         
  1. import org.springframework.security.web.context.*;
  2. public class SecurityWebApplicationInitializer
  3. extends AbstractSecurityWebApplicationInitializer {
  4. public SecurityWebApplicationInitializer() {
  5. super(WebSecurityConfig.class);
  6. }
  7. }

SecurityWebApplicationInitializer将执行以下操作:

  • 为应用程序中的每个URL自动注册springSecurityFilterChain过滤器

  • 添加加载WebSecurityConfig的ContextLoaderListener。

具有Spring MVC的AbstractSecurityWebApplicationInitializer。====

如果我们在应用程序的其他地方使用Spring,我们可能已经有一个加载我们的Spring配置的WebApplicationInitializer。 如果我们使用以前的配置,我们会得到一个错误。 相反,我们应该使用现有的ApplicationContext注册Spring Security。 例如,如果我们使用Spring MVC,我们的SecurityWebApplicationInitializer将如下所示:


         
         
  1. import org.springframework.security.web.context.*;
  2. public class SecurityWebApplicationInitializer
  3. extends AbstractSecurityWebApplicationInitializer {
  4. }

这只会为应用程序中的每个URL注册springSecurityFilterChain过滤器。 之后,我们将确保WebSecurityConfig在我们现有的ApplicationInitializer中加载。 例如,如果我们使用Spring MVC,它将被添加到getRootConfigClasses()


         
         
  1. public class MvcWebApplicationInitializer extends
  2. AbstractAnnotationConfigDispatcherServletInitializer {
  3. @Override
  4. protected Class<?>[] getRootConfigClasses() {
  5. return new Class[] { WebSecurityConfig.class };
  6. }
  7. // ... other overrides ...
  8. }

HttpSecurity

迄今为止,我们的WebSecurityConfig仅包含有关如何验证用户的信息。 Spring Security如何知道我们想要求所有用户进行身份验证? Spring Security如何知道我们想要支持基于表单的身份验证?原因是WebSecurityConfigurerAdapterconfigure(HttpSecurity http)方法中提供了一个默认配置,如下所示:


        
        
  1. protected void configure(HttpSecurity http) throws Exception {
  2. http
  3. .authorizeRequests()
  4. .anyRequest().authenticated()
  5. .and()
  6. .formLogin()
  7. .and()
  8. .httpBasic();
  9. }

上面的默认配置:

  • 确保对我们应用程序的任何请求都要求用户进行身份验证

  • 允许用户使用基于表单的登录进行身份验证

  • 允许用户使用HTTP基本身份验证进行身份验证

您会注意到这个配置与XML命名空间配置非常相似:


        
        
  1. <http>
  2. <intercept-url pattern="/**" access="authenticated"/>
  3. <form-login />
  4. <http-basic />
  5. </http>

关闭XML标签的Java配置等同于使用允许我们继续配置父项的and()方法表示。 如果你阅读代码,这也是有道理的。 我想配置授权请求并配置表单登录and__配置HTTP基本认证。

Java配置和表单登录

由于我们没有提及任何HTML文件或JSP,因此您可能想知道登录表单从何时被提示登录。 由于Spring Security的默认配置没有明确设置登录页面的URL,因此Spring Security会根据启用的功能自动生成一个URL,并使用处理提交的登录的URL的标准值,用户将默认的目标URL登录后发送到等等。

尽管自动生成的登录页面很方便快速启动和运行,但大多数应用程序都希望提供自己的登录页面。 为此,我们可以更新我们的配置,如下所示:


        
        
  1. protected void configure(HttpSecurity http) throws Exception {
  2. http
  3. .authorizeRequests()
  4. .anyRequest().authenticated()
  5. .and()
  6. .formLogin()
  7. .loginPage("/login")
  8. .permitAll();
  9. }

<1>更新后的配置指定登录页面的位置。 <2>我们必须授予所有用户(即未经身份验证的用户)访问我们的登录页面。formLogin().permitAll()方法允许所有用户访问与基于表单的登录相关的所有URL。

下面是一个使用JSP实现的用于当前配置的登录页面示例:

注意:下面的登录页面代表我们当前的配置。 如果某些默认设置不能满足我们的需求,我们可以轻松更新我们的配置。


        
        
  1. <c:url value="/login" var="loginUrl"/>
  2. <form action="${loginUrl}" method="post">
  3. <c:if test="${param.error != null}">
  4. <p>
  5. Invalid username and password.
  6. </p>
  7. </c:if>
  8. <c:if test="${param.logout != null}">
  9. <p>
  10. You have been logged out.
  11. </p>
  12. </c:if>
  13. <p>
  14. <label for="username">Username</label>
  15. <input type="text" id="username" name="username"/>
  16. </p>
  17. <p>
  18. <label for="password">Password</label>
  19. <input type="password" id="password" name="password"/>
  20. </p>
  21. <input type="hidden"
  22. name="${_csrf.parameterName}"
  23. value="${_csrf.token}"/>
  24. <button type="submit" class="btn">Log in</button>
  25. </form>

<1>发布到/login网址的邮件将尝试对用户进行身份验证 <2>如果查询参数error存在,则认证尝试失败 <3>如果查询参数logout存在,用户已成功注销 <4>用户名必须作为名为username的HTTP参数存在 <5>密码必须以名为password的HTTP参数 <6>我们必须包含CSRF令牌要了解更多信息,请阅读参考文献的跨网站请求伪造(CSRF)部分

授权请求

我们的示例只需要用户进行身份验证,并已为我们的应用程序中的每个URL完成此操作。 我们可以通过向我们的http.authorizeRequests()方法添加多个子项来为我们的网址指定自定义要求。 例如:


        
        
  1. protected void configure(HttpSecurity http) throws Exception {
  2. http
  3. .authorizeRequests()
  4. .antMatchers("/resources/**", "/signup", "/about").permitAll()
  5. .antMatchers("/admin/**").hasRole("ADMIN")
  6. .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
  7. .anyRequest().authenticated()
  8. .and()
  9. // ...
  10. .formLogin();
  11. }
 http.authorizeRequests()方法有多个孩子,每个匹配者按照他们声明的顺序考虑。 <2>我们指定了任何用户都可以访问的多个网址格式。 具体而言,如果网址以"/resources/"开头,等于"/signup"或等于"/about",任何用户都可以访问请求。 <3>任何以"/admin/"开头的网址将仅限于拥有角色"ROLE_ADMIN"的用户。 您会注意到,由于我们调用了hasRole方法,因此我们不需要指定"ROLE_"前缀。 <4>任何以"/db/"开头的网址都需要用户同时拥有"ROLE_ADMIN"和"ROLE_DBA"。 您会注意到,由于我们使用的是hasRole表达式,因此无需指定"ROLE_"前缀。 <5>任何尚未匹配的网址只要求用户进行身份验证

处理注销

使用WebSecurityConfigurerAdapter时,会自动应用注销功能。 默认情况下,访问网址/logout将通过以下方式登录用户:

  • 使HTTP会话无效

  • 清理已配置的任何RememberMe认证

  • 清除SecurityContextHolder

  • 重定向到/login?logout

但是,类似于配置登录功能,您还可以有多种选项来进一步自定义注销要求:


        
        
  1. protected void configure(HttpSecurity http) throws Exception {
  2. http
  3. .logout()
  4. .logoutUrl("/my/logout")
  5. .logoutSuccessUrl("/my/index")
  6. .logoutSuccessHandler(logoutSuccessHandler)
  7. .invalidateHttpSession(true)
  8. .addLogoutHandler(logoutHandler)
  9. .deleteCookies(cookieNamesToClear)
  10. .and()
  11. ...
  12. }

<1>提供注销支持。 这在使用WebSecurityConfigurerAdapter时会自动应用。 <2>触发注销的URL(默认为/logout)。 如果启用CSRF保护(默认),则该请求也必须是POST。 有关更多信息,请参阅http://docs.spring.io/spring-security/site/docs/current/apidocs/ org / springframework / security / config / annotation / web / configurers / LogoutConfigurer.html#logoutUrl-java.lang.String- [JavaDoc]。 <3>发生注销后重定向到的URL。 默认值是/login?logout。 有关更多信息,请参阅http://docs.spring.io/spring-security/site/docs/current/apidocs/ org / springframework / security / config / annotation / web / configurers / LogoutConfigurer.html#logoutSuccessUrl-java.lang.String- [JavaDoc]。 <4>让我们指定一个自定义LogoutSuccessHandler。 如果指定,则logoutSuccessUrl()被忽略。 有关更多信息,请参阅http://docs.spring.io/spring-security/site/docs/current/apidocs/ org / springframework / security / config / annotation / web / configurers / LogoutConfigurer.html#logoutSuccessHandler-org.springframework.security.web.authentication.logout.LogoutSuccessHandler- [JavaDoc ]。 <5>指定在注销时是否使HttpSession无效。 这是默认的true。 配置封面下的{{0}。 有关更多信息,请参阅http://docs.spring.io/spring-security/site/docs/current/apidocs/ org / springframework / security / config / annotation / web / configurers / LogoutConfigurer.html#invalidateHttpSession-boolean- [JavaDoc]。 <6>添加一个LogoutHandler。 SecurityContextLogoutHandler默认添加为最后一个LogoutHandler。 <7>允许指定在注销成功时删除的cookies的名称。 这是明确添加CookieClearingLogoutHandler的快捷方式。

 

注销当然也可以使用XML名称空间表示法进行配置。 有关更多详细信息,请参阅Spring Security XML命名空间部分中logout element的文档。

通常,为了自定义注销功能,您可以添加 LogoutHandler 和/或 LogoutSuccessHandler 实现。 对于很多常见的场景,这些处理程序都是根据 涵盖了何时使用流利的API。

LogoutHandler

通常,LogoutHandler 实现指示能够参与注销处理的类。 预计它们将被调用来执行必要的清理。 因此他们应该 不会抛出异常。 提供了各种实现:

  • {安全API-URL}组织/ springframework的/安全/网络/认证/了rememberMe / PersistentTokenBasedRememberMeServices.html [对PersistentTokenBasedRememberMeServices]

  • {安全API-URL}组织/ springframework的/安全/网络/认证/了rememberMe / TokenBasedRememberMeServices.html [TokenBasedRememberMeServices]

  • {安全API-URL}组织/ springframework的/安全/网络/认证/注销/ CookieClearingLogoutHandler.html [CookieClearingLogoutHandler]

  • {安全API-URL}组织/ springframework的/安全/网络/ CSRF / CsrfLogoutHandler.html [CsrfLogoutHandler]

  • {安全API-URL}组织/ springframework的/安全/网络/认证/注销/ SecurityContextLogoutHandler.html [SecurityContextLogoutHandler]

有关详细信息,请参阅记住我的接口和实现

Fluent API不是直接提供LogoutHandler实现,而是提供了快捷方式,它们提供了相应的LogoutHandler实现。 例如。 deleteCookies()允许指定在注销成功时删除一个或多个Cookie的名称。 与添加CookieClearingLogoutHandler相比,这是一条捷径。

LogoutSuccessHandler

LogoutFilter成功注销后调用LogoutSuccessHandler,以处理例如 重定向或转发到适当的目的地。 请注意,界面与LogoutHandler几乎相同,但可能会引发异常。

提供了以下实现:

  • {安全API-URL}组织/ springframework的/安全/网络/认证/注销/ SimpleUrlLogoutSuccessHandler.html [SimpleUrlLogoutSuccessHandler]

  • HttpStatusReturningLogoutSuccessHandler

如上所述,您不需要直接指定SimpleUrlLogoutSuccessHandler。 相反,流利的API通过设置logoutSuccessUrl()来提供快捷方式。 这将设置封面下的SimpleUrlLogoutSuccessHandler。 提供的URL将在注销发生后重定向到。 默认值是/login?logout

REST API类型场景中的HttpStatusReturningLogoutSuccessHandler可能很有趣。 取而代之的是在成功注销后重定向到URL,这个LogoutSuccessHandler允许您提供一个简单的HTTP状态代码来返回。 如果未配置,则缺省情况下将返回状态代码200。

更多注销相关参考

WebFlux安全

Spring Security的WebFlux支持依赖于WebFilter,并且对于Spring WebFlux和Spring WebFlux.Fn也是如此。 你可以找到几个示例应用程序来演示下面的代码:

  • Hello WebFlux {gh-samples-url} / javaconfig / hellowebflux [hellowebflux]

  • Hello WebFlux.Fn {gh-samples-url} / javaconfig / hellowebfluxfn [hellowebfluxfn]

  • Hello WebFlux方法{gh-samples-url} / javaconfig / hellowebflux-method [hellowebflux-method]

最小的WebFlux安全配置

您可以在下面找到最低限度的WebFlux安全配置:


         
         
  1. @EnableWebFluxSecurity
  2. public class HelloWebfluxSecurityConfig {
  3. @Bean
  4. public MapReactiveUserDetailsService userDetailsService() {
  5. UserDetails user = User.withDefaultPasswordEncoder()
  6. .username("user")
  7. .password("user")
  8. .roles("USER")
  9. .build();
  10. return new MapReactiveUserDetailsService(user);
  11. }
  12. }

此配置提供表单和http基本身份验证,设置授权以要求经过身份验证的用户访问任何页面,设置默认登录页面和默认注销页面,设置与安全性相关的HTTP标头,CSRF保护等。

明确的WebFlux安全配置

您可以在下面找到最小WebFlux安全配置的显式版本:


         
         
  1. @EnableWebFluxSecurity
  2. public class HelloWebfluxSecurityConfig {
  3. @Bean
  4. public MapReactiveUserDetailsService userDetailsService() {
  5. UserDetails user = User.withDefaultPasswordEncoder()
  6. .username("user")
  7. .password("user")
  8. .roles("USER")
  9. .build();
  10. return new MapReactiveUserDetailsService(user);
  11. }
  12. @Bean
  13. public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
  14. http
  15. .authorizeExchange()
  16. .anyExchange().authenticated()
  17. .and()
  18. .httpBasic().and()
  19. .formLogin();
  20. return http.build();
  21. }
  22. }

该配置明确设置了与我们最小配置相同的所有内容。 从这里您可以轻松地对默认值进行更改。

OAuth 2.0登录

OAuth 2.0登录功能为应用程序提供了让用户通过在OAuth 2.0提供者处使用其现有帐户登录应用程序的功能(例如, GitHub)或OpenID Connect 1.0 Provider(例如Google)。 OAuth 2.0 Login实现了用例:"Login with Google"或"Login with GitHub"。

注意:通过使用https://tools.ietf.org/html/rfc6749#section-4.1[OAuth 2.0授权框架]和 OpenID Connect Core 1.0中指定的Authorization Code Grant实现OAuth 2.0登录。

Spring Boot 2.0示例

Spring Boot 2.0为OAuth 2.0登录带来了全面的自动配置功能。

本节介绍如何使用Google作为Authentication Provider配置{gh-samples-url} / boot / oauth2login [OAuth 2.0 Login sample],并涵盖以下主题:

初始设置

要使用Google的OAuth 2.0身份验证系统进行登录,您必须在Google API控制台中设置一个项目以获取OAuth 2.0凭据。

注意:用于身份验证的https://developers.google.com/identity/protocols/OpenIDConnect[Google' OAuth 2.0实现]符合 OpenID Connect 1.0规范,并且是 OpenID认证

按照https://developers.google.com/identity/protocols/OpenIDConnect[OpenID Connect]页上的说明操作,从"Setting up OAuth 2.0"部分开始。

完成"Obtain OAuth 2.0 credentials"指示后,您应该拥有一个新的OAuth客户端,其凭据由客户端ID和客户端密钥组成。

设置重定向URI

重定向URI是应用程序中的路径,用户的用户代理在与Google进行身份验证并授予对“同意”页面上的OAuth客户端created in the previous step的访问权之后,会将其重定向回。

在"Set a redirect URI"小节中,确保Authorized redirect URIs字段设置为http://localhost:8080/login/oauth2/code/google

提示:默认重定向URI模板为{baseUrl}/login/oauth2/code/{registrationId}。 registrationIdClientRegistration的唯一标识符。

配置application.yml

现在,您已经拥有了一个带有Google的新OAuth客户端,您需要配置该应用程序以使用OAuth客户端作为authentication flow。 要做到这一点:

  1. 转到application.yml并设置以下配置:

    spring:
      security:
        oauth2:
          client:
            registration:	
              google:	
                client-id: google-client-id
                client-secret: google-client-secret
    Example 1. OAuth客户端属性
     spring.security.oauth2.client.registration是OAuth客户端属性的基本属性前缀。 <2>基本属性前缀后面是ClientRegistration的ID,例如google。
  2. 用您之前创建的OAuth 2.0凭据替换client-idclient-secret属性中的值。

启动应用程序

启动Spring Boot 2.0示例并转至http://localhost:8080。 然后,您被重定向到默认的auto-generated登录页面,该页面显示Google的链接。

点击Google链接,然后重定向到Google进行身份验证。

在使用Google帐户凭证进行身份验证后,向您呈现的下一页是“同意”屏幕。 “同意”屏幕会要求您允许或拒绝访问之前创建的OAuth客户端。 点击Allow,授权OAuth客户端访问您的电子邮件地址和基本配置文件信息。

此时,OAuth客户端会从 UserInfo端点中检索您的电子邮件地址和基本配置文件信息,并建立经过验证的会话。

ClientRegistration

ClientRegistration是向OAuth 2.0或OpenID Connect 1.0 Provider注册的客户端的代表。

客户端注册保存信息,如客户端ID,客户端密码, 授权授权类型,重定向URI,范围,授权URI,令牌URI和其他详细信息。

ClientRegistration及其属性定义如下:


         
         
  1. public final class ClientRegistration {
  2. private String registrationId;
  3. private String clientId;
  4. private String clientSecret;
  5. private ClientAuthenticationMethod clientAuthenticationMethod;
  6. private AuthorizationGrantType authorizationGrantType;
  7. private String redirectUriTemplate;
  8. private Set<String> scopes;
  9. private ProviderDetails providerDetails;
  10. private String clientName;
  11. public class ProviderDetails {
  12. private String authorizationUri;
  13. private String tokenUri;
  14. private UserInfoEndpoint userInfoEndpoint;
  15. private String jwkSetUri;
  16. public class UserInfoEndpoint {
  17. private String uri;
  18. private String userNameAttributeName;
  19. }
  20. }
  21. }
 registrationId:唯一标识ClientRegistration的标识。
 clientId:客户端标识符。
 clientSecret:客户端秘密。
 clientAuthenticationMethod:用于向提供者验证客户端的方法。 支持的值是basicpost
 authorizationGrantType:OAuth 2.0授权框架定义了四个https://tools.ietf.org/html/rfc6749#section-1.3 [授权]类型。 支持的值是authorization_code和隐式。
 redirectUriTemplate:客户端注册的重定向URI,Authorization Server重定向最终用户的用户代理 到最终用户已验证并授权访问客户端后。 默认的重定向URI模板是{baseUrl}/login/oauth2/code/{registrationId},它支持URI模板变量。
 scopes:客户端在授权请求流程中请求的范围,例如openid,电子邮件或配置文件。
 clientName:用于客户端的描述性名称。 该名称可用于某些情况下,例如在自动生成的登录页面中显示客户端的名称时。
 authorizationUri:授权服务器的授权端点URI。
 tokenUri:授权服务器的令牌端点URI。
 jwkSetUri:用于检索https://tools.ietf.org/html/rfc7517[JSON Web Key(JWK)]的URI从授权服务器设置, ,其中包含用于验证ID令牌的https://tools.ietf.org/html/rfc7515[JSON Web签名(JWS)]的加密密钥以及可选的UserInfo响应。
 (userInfoEndpoint)uri:UserInfo端点URI,用于访问经过身份验证的最终用户的声明/属性。
 userNameAttributeName:在UserInfo Response中返回的属性的名称,该名称引用最终用户的名称或标识符。
Spring Boot 2.0属性映射

下表概述了Spring Boot 2.0 OAuth客户端属性到ClientRegistration属性的映射。

Spring Boot 2.0ClientRegistration

spring.security.oauth2.client.registration.[registrationId]

registrationId

spring.security.oauth2.client.registration.[registrationId].client-id

clientId

spring.security.oauth2.client.registration.[registrationId].client-secret

clientSecret

spring.security.oauth2.client.registration.[registrationId].client-authentication-method

clientAuthenticationMethod

spring.security.oauth2.client.registration.[registrationId].authorization-grant-type

authorizationGrantType

spring.security.oauth2.client.registration.[registrationId].redirect-uri-template

redirectUriTemplate

spring.security.oauth2.client.registration.[registrationId].scope

scopes

spring.security.oauth2.client.registration.[registrationId].client-name

clientName

spring.security.oauth2.client.provider.[providerId].authorization-uri

providerDetails.authorizationUri

spring.security.oauth2.client.provider.[providerId].token-uri

providerDetails.tokenUri

spring.security.oauth2.client.provider.[providerId].jwk-set-uri

providerDetails.jwkSetUri

spring.security.oauth2.client.provider.[providerId].user-info-uri

providerDetails.userInfoEndpoint.uri

spring.security.oauth2.client.provider.[providerId].userNameAttribute

providerDetails.userInfoEndpoint.userNameAttributeName

ClientRegistrationRepository

ClientRegistrationRepository充当OAuth 2.0 / OpenID Connect 1.0 ClientRegistration(s)的存储库。

 客户端注册信息最终由关联的授权服务器存储和拥有。 该存储库提供了检索主要客户端注册信息的子集的能力, 它与授权服务器一起存储。

Spring Boot 2.0自动配置绑定spring.security.oauth2.client.registration.[registrationId]下的每个属性 到ClientRegistration的实例,然后在ClientRegistrationRepository内组合ClientRegistration个实例中的每个实例。

 ClientRegistrationRepository的默认实现是InMemoryClientRegistrationRepository

自动配置还将ClientRegistrationRepository注册为ApplicationContext中的@Bean 以便它可用于依赖注入,如果应用程序需要的话。

以下列表显示了一个示例:


         
         
  1. @Controller
  2. public class OAuth2LoginController {
  3. @Autowired
  4. private ClientRegistrationRepository clientRegistrationRepository;
  5. @RequestMapping("/")
  6. public String index() {
  7. ClientRegistration googleRegistration =
  8. this.clientRegistrationRepository.findByRegistrationId("google");
  9. ...
  10. return "index";
  11. }
  12. }
CommonOAuth2Provider

CommonOAuth2Provider为众多知名供应商预先定义了一组默认客户端属性:Google,GitHub,Facebook和Okta。

例如,authorization-uritoken-uriuser-info-uri不会经常更改提供者。 因此,提供默认值以减少所需的配置是有意义的。

如前所述,当我们configured a Google client时,只需要client-idclient-secret属性。

以下列表显示了一个示例:

spring:
  security:
    oauth2:
      client:
        registration:
          google:
            client-id: google-client-id
            client-secret: google-client-secret
 由于registrationIdgoogle)与CommonOAuth2Provider中的GOOGLE enum(不区分大小写)匹配,所以客户端属性的自动默认功能无缝工作。

对于您可能需要指定不同的registrationId的情况,例如google-login, 您仍然可以通过配置provider属性来利用客户端属性的自动默认功能。

以下列表显示了一个示例:

spring:
  security:
    oauth2:
      client:
        registration:
          google-login:	
            provider: google	
            client-id: google-client-id
            client-secret: google-client-secret
 registrationId设置为google-login
 provider属性设置为google,该属性将利用CommonOAuth2Provider.GOOGLE.getBuilder()中设置的客户端属性的自动默认设置。
配置自定义提供程序属性

有一些OAuth 2.0提供商支持多租户,这会为每个租户(或子域)生成不同的协议端点。

例如,向Okta注册的OAuth客户端分配给特定的子域,并拥有自己的协议端点。

对于这些情况,Spring Boot 2.0为配置自定义提供程序属性提供以下基本属性:spring.security.oauth2.client.provider.[providerId]

以下列表显示了一个示例:

spring:
  security:
    oauth2:
      client:
        registration:
          okta:
            client-id: okta-client-id
            client-secret: okta-client-secret
        provider:
          okta:	
            authorization-uri: https://your-subdomain.oktapreview.com/oauth2/v1/authorize
            token-uri: https://your-subdomain.oktapreview.com/oauth2/v1/token
            user-info-uri: https://your-subdomain.oktapreview.com/oauth2/v1/userinfo
            user-name-attribute: sub
            jwk-set-uri: https://your-subdomain.oktapreview.com/oauth2/v1/keys

<1>基本属性(spring.security.oauth2.client.provider.okta)允许自定义配置协议端点位置。

重写Spring Boot 2.0自动配置

用于OAuth客户端支持的Spring Boot 2.0自动配置类为OAuth2ClientAutoConfiguration

它执行以下任务:

  • 从配置的OAuth客户端属性中注册由ClientRegistration(s)组成的ClientRegistrationRepository @Bean

  • 提供WebSecurityConfigurerAdapter @Configuration并通过httpSecurity.oauth2Login()启用OAuth 2.0登录。

如果您需要根据您的特定要求覆盖自动配置,可以通过以下方式进行:

注册一个ClientRegistrationRepository @Bean

以下示例显示如何注册ClientRegistrationRepository @Bean


          
          
  1. @Configuration
  2. public class OAuth2LoginConfig {
  3. @Bean
  4. public ClientRegistrationRepository clientRegistrationRepository() {
  5. return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
  6. }
  7. private ClientRegistration googleClientRegistration() {
  8. return ClientRegistration.withRegistrationId("google")
  9. .clientId("google-client-id")
  10. .clientSecret("google-client-secret")
  11. .clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
  12. .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
  13. .redirectUriTemplate("{baseUrl}/login/oauth2/code/{registrationId}")
  14. .scope("openid", "profile", "email", "address", "phone")
  15. .authorizationUri("https://accounts.google.com/o/oauth2/v2/auth")
  16. .tokenUri("https://www.googleapis.com/oauth2/v4/token")
  17. .userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
  18. .userNameAttributeName(IdTokenClaimNames.SUB)
  19. .jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
  20. .clientName("Google")
  21. .build();
  22. }
  23. }
提供WebSecurityConfigurerAdapter

以下示例显示如何为WebSecurityConfigurerAdapter提供@EnableWebSecurity,并通过httpSecurity.oauth2Login()启用OAuth 2.0登录:


          
          
  1. @EnableWebSecurity
  2. public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
  3. @Override
  4. protected void configure(HttpSecurity http) throws Exception {
  5. http
  6. .authorizeRequests()
  7. .anyRequest().authenticated()
  8. .and()
  9. .oauth2Login();
  10. }
  11. }
完全覆盖自动配置

以下示例显示了如何通过注册ClientRegistrationRepository @Bean并提供WebSecurityConfigurerAdapter完全覆盖自动配置,两者均在前两节中进行了介绍。


          
          
  1. @Configuration
  2. public class OAuth2LoginConfig {
  3. @EnableWebSecurity
  4. public static class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
  5. @Override
  6. protected void configure(HttpSecurity http) throws Exception {
  7. http
  8. .authorizeRequests()
  9. .anyRequest().authenticated()
  10. .and()
  11. .oauth2Login();
  12. }
  13. }
  14. @Bean
  15. public ClientRegistrationRepository clientRegistrationRepository() {
  16. return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
  17. }
  18. private ClientRegistration googleClientRegistration() {
  19. return ClientRegistration.withRegistrationId("google")
  20. .clientId("google-client-id")
  21. .clientSecret("google-client-secret")
  22. .clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
  23. .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
  24. .redirectUriTemplate("{baseUrl}/login/oauth2/code/{registrationId}")
  25. .scope("openid", "profile", "email", "address", "phone")
  26. .authorizationUri("https://accounts.google.com/o/oauth2/v2/auth")
  27. .tokenUri("https://www.googleapis.com/oauth2/v4/token")
  28. .userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
  29. .userNameAttributeName(IdTokenClaimNames.SUB)
  30. .jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
  31. .clientName("Google")
  32. .build();
  33. }
  34. }

没有Spring Boot 2.0的==== Java配置

如果您无法使用Spring Boot 2.0并希望在CommonOAuth2Provider中配置一个预定义提供程序(例如Google),请应用以下配置:


          
          
  1. @Configuration
  2. public class OAuth2LoginConfig {
  3. @EnableWebSecurity
  4. public static class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
  5. @Override
  6. protected void configure(HttpSecurity http) throws Exception {
  7. http
  8. .authorizeRequests()
  9. .anyRequest().authenticated()
  10. .and()
  11. .oauth2Login();
  12. }
  13. }
  14. @Bean
  15. public ClientRegistrationRepository clientRegistrationRepository() {
  16. return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
  17. }
  18. @Bean
  19. public OAuth2AuthorizedClientService authorizedClientService() {
  20. return new InMemoryOAuth2AuthorizedClientService(this.clientRegistrationRepository());
  21. }
  22. private ClientRegistration googleClientRegistration() {
  23. return CommonOAuth2Provider.GOOGLE.getBuilder("google")
  24. .clientId("google-client-id")
  25. .clientSecret("google-client-secret")
  26. .build();
  27. }
  28. }
OAuth2AuthorizedClient / OAuth2AuthorizedClientService

OAuth2AuthorizedClient是授权客户端的代表。 当最终用户(资源所有者)授予客户端访问其受保护资源的权限时,客户端被认为是被授权的。

OAuth2AuthorizedClient用于将OAuth2AccessTokenClientRegistration(客户端)和资源所有者关联起来,该所有者是授予授权的Principal最终用户。

OAuth2AuthorizedClientService的主要作用是管理OAuth2AuthorizedClient个实例。 从开发人员的角度来看,它提供了查找与客户端关联的OAuth2AccessToken的功能,以便它可以用来发起对资源服务器的请求。

 Spring Boot 2.0自动配置在ApplicationContext中注册OAuth2AuthorizedClientService @Bean

开发人员还可以在ApplicationContext(覆盖Spring Boot 2.0自动配置)中注册OAuth2AuthorizedClientService@Bean,以便能够查找与特定相关的OAuth2AccessToken ClientRegistration(客户端)。

以下列表显示了一个示例:


         
         
  1. @Controller
  2. public class OAuth2LoginController {
  3. @Autowired
  4. private OAuth2AuthorizedClientService authorizedClientService;
  5. @RequestMapping("/userinfo")
  6. public String userinfo(OAuth2AuthenticationToken authentication) {
  7. // authentication.getAuthorizedClientRegistrationId() returns the
  8. // registrationId of the Client that was authorized during the Login flow
  9. OAuth2AuthorizedClient authorizedClient =
  10. this.authorizedClientService.loadAuthorizedClient(
  11. authentication.getAuthorizedClientRegistrationId(),
  12. authentication.getName());
  13. OAuth2AccessToken accessToken = authorizedClient.getAccessToken();
  14. ...
  15. return "userinfo";
  16. }
  17. }

认证

到目前为止,我们只看到了最基本的认证配置。 让我们来看看几个稍微更高级的配置认证选项。

内存认证

我们已经看到了为单个用户配置内存认证的例子。 以下是配置多个用户的示例:


         
         
  1. @Bean
  2. public UserDetailsService userDetailsService() throws Exception {
  3. // ensure the passwords are encoded properly
  4. UserBuilder users = User.withDefaultPasswordEncoder();
  5. InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
  6. manager.createUser(users.username("user").password("password").roles("USER").build());
  7. manager.createUser(users.username("admin").password("password").roles("USER","ADMIN").build());
  8. return manager;
  9. }
JDBC身份验证

您可以找到更新以支持基于JDBC的身份验证。 以下示例假定您已经在应用程序中定义了DataSource。 jdbc-javaconfig示例提供了使用基于JDBC的身份验证的完整示例。


         
         
  1. @Autowired
  2. private DataSource dataSource;
  3. @Autowired
  4. public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
  5. // ensure the passwords are encoded properly
  6. UserBuilder users = User.withDefaultPasswordEncoder();
  7. auth
  8. .jdbcAuthentication()
  9. .dataSource(dataSource)
  10. .withDefaultSchema()
  11. .withUser(users.username("user").password("password").roles("USER"))
  12. .withUser(users.username("admin").password("password").roles("USER","ADMIN"));
  13. }
LDAP身份验证

您可以找到更新以支持基于LDAP的身份验证。 ldap-javaconfig示例提供了使用基于LDAP的身份验证的完整示例。


         
         
  1. @Autowired
  2. private DataSource dataSource;
  3. @Autowired
  4. public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
  5. auth
  6. .ldapAuthentication()
  7. .userDnPatterns("uid={0},ou=people")
  8. .groupSearchBase("ou=groups");
  9. }

上面的示例使用以下LDIF和嵌入式Apache DS LDAP实例。

users.ldif
dn: ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: groups

dn: ou=people,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: people

dn: uid=admin,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Rod Johnson
sn: Johnson
uid: admin
userPassword: password

dn: uid=user,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Dianne Emu
sn: Emu
uid: user
userPassword: password

dn: cn=user,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfNames
cn: user
uniqueMember: uid=admin,ou=people,dc=springframework,dc=org
uniqueMember: uid=user,ou=people,dc=springframework,dc=org

dn: cn=admin,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfNames
cn: admin
uniqueMember: uid=admin,ou=people,dc=springframework,dc=org

的AuthenticationProvider

您可以通过将自定义AuthenticationProvider公开为bean来定义自定义身份验证。 例如,假设SpringAuthenticationProvider实现AuthenticationProvider,以下将自定义认证:

注:仅当AuthenticationManagerBuilder尚未填充时才会使用


    
    
  1. @Bean
  2. public SpringAuthenticationProvider springAuthenticationProvider() {
  3. return new SpringAuthenticationProvider();
  4. }
的UserDetailsS​​ervice

您可以通过将自定义UserDetailsService公开为bean来定义自定义身份验证。 例如,假设SpringDataUserDetailsService实现UserDetailsService,以下将自定义认证:

注意:仅当AuthenticationManagerBuilder尚未填充且未定义AuthenticationProviderBean时才会使用此选项。


    
    
  1. @Bean
  2. public SpringDataUserDetailsService springDataUserDetailsService() {
  3. return new SpringDataUserDetailsService();
  4. }

您还可以通过将PasswordEncoder公开为bean来自定义密码的编码方式。 例如,如果您使用bcrypt,则可以添加一个bean定义,如下所示:


    
    
  1. @Bean
  2. public BCryptPasswordEncoder passwordEncoder() {
  3. return new BCryptPasswordEncoder();
  4. }

多个HttpSecurity

我们可以配置多个HttpSecurity实例,就像我们可以有多个<http>块一样。 关键是多次扩展WebSecurityConfigurationAdapter。 例如,以下是针对以/api/开头的URL进行不同配置的示例。


    
    
  1. @EnableWebSecurity
  2. public class MultiHttpSecurityConfig {
  3. @Bean
  4. public UserDetailsService userDetailsService() throws Exception {
  5. // ensure the passwords are encoded properly
  6. UserBuilder users = User.withDefaultPasswordEncoder();
  7. InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
  8. manager.createUser(users.username(“user”).password(“password”).roles(“USER”).build());
  9. manager.createUser(users.username(“admin”).password(“password”).roles(“USER”,“ADMIN”).build());
  10. return manager;
  11. }
  12. @Configuration
  13. @Order(1)
  14. public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
  15. protected void configure(HttpSecurity http) throws Exception {
  16. http
  17. .antMatcher("/api/**")
  18. .authorizeRequests()
  19. .anyRequest().hasRole(“ADMIN”)
  20. .and()
  21. .httpBasic();
  22. }
  23. }
  24. @Configuration
  25. public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
  26. @Override
  27. protected void configure(HttpSecurity http) throws Exception {
  28. http
  29. .authorizeRequests()
  30. .anyRequest().authenticated()
  31. .and()
  32. .formLogin();
  33. }
  34. }
  35. }

<1>配置身份验证正常 <2>创建包含@OrderWebSecurityConfigurerAdapter的实例,以指定首先考虑哪个WebSecurityConfigurerAdapter。 <3> http.antMatcher声明,此HttpSecurity仅适用于以/api/开头的网址 <4>创建WebSecurityConfigurerAdapter的另一个实例。 如果网址不是以/api/开头,则会使用此配置。ApiWebSecurityConfigurationAdapter之后会考虑此配置,因为1@Order默认为最后一个值)后有@Order值。

方法安全性

从2.0版本开始,Spring Security已经大大改善了对服务层方法的安全性的支持。 它提供对JSR-250注释安全性的支持以及框架的原始@Secured注释。 从3.0开始,您还可以使用新的expression-based annotations。 您可以使用intercept-methods元素来装饰bean声明,也可以将安全性应用于单个bean,也可以使用AspectJ样式切入点在整个服务层中保护多个bean。

EnableGlobalMethodSecurity

我们可以在任何@Configuration实例上使用@EnableGlobalMethodSecurity注释来启用基于注释的安全性。 例如,以下内容将启用Spring Security的@Secured注释。


     
     
  1. @EnableGlobalMethodSecurity(securedEnabled = true)
  2. public class MethodSecurityConfig {
  3. // …
  4. }

然后向方法(在类或接口上)添加注释将相应地限制对该方法的访问。 Spring Security的本地注释支持为该方法定义了一组属性。 这些将被传递给AccessDecisionManager以供它作出实际的决定:


     
     
  1. public interface BankService {
  2. @Secured(“IS_AUTHENTICATED_ANONYMOUSLY”)
  3. public Account readAccount(Long id);
  4. @Secured(“IS_AUTHENTICATED_ANONYMOUSLY”)
  5. public Account[] findAccounts();
  6. @Secured(“ROLE_TELLER”)
  7. public Account post(Account account, double amount);
  8. }

可以使用支持JSR-250注释


     
     
  1. @EnableGlobalMethodSecurity(jsr250Enabled = true)
  2. public class MethodSecurityConfig {
  3. // …
  4. }

这些都是基于标准的,允许应用简单的基于角色的约束,但是没有Spring Security的本地注释的强大功能。 要使用新的基于表达式的语法,您可以使用


     
     
  1. @EnableGlobalMethodSecurity(prePostEnabled = true)
  2. public class MethodSecurityConfig {
  3. // …
  4. }

和等效的Java代码将会是


     
     
  1. public interface BankService {
  2. @PreAuthorize(“isAnonymous()”)
  3. public Account readAccount(Long id);
  4. @PreAuthorize(“isAnonymous()”)
  5. public Account[] findAccounts();
  6. @PreAuthorize(“hasAuthority(‘ROLE_TELLER’)”)
  7. public Account post(Account account, double amount);
  8. }
GlobalMethodSecurityConfiguration

有时您可能需要执行比@EnableGlobalMethodSecurity批注允许的操作更复杂的操作。 对于这些实例,您可以扩展GlobalMethodSecurityConfiguration,确保@EnableGlobalMethodSecurity注释存在于您的子类中。 例如,如果您想提供自定义MethodSecurityExpressionHandler,则可以使用以下配置:


     
     
  1. @EnableGlobalMethodSecurity(prePostEnabled = true)
  2. public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
  3. @Override
  4. protected MethodSecurityExpressionHandler createExpressionHandler() {
  5. // … create and return custom MethodSecurityExpressionHandler …
  6. return expressionHandler;
  7. }
    </div

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值