在本章中,我们将介绍 Spring Security 的基础知识。这是 Spring Framework 的重要组成部分,所以慢慢来。我们将涵盖以下主题:
- Introducing Spring Security
- Defining user roles
- Defining data transfer objects (DTOs) for users
- Providing authentication
- Providing authorization
在本章中,我们将介绍 Spring Security 的基础知识。这是 Spring Framework 的重要组成部分,所以慢慢来。我们将涵盖以下主题:
顾名思义,Spring Security 代表了具有各种与安全相关的强大功能的框架。它提供了一个高度可定制的身份验证和访问控制框架。在现代开发中,Spring Security 是保护基于 Spring Framework 的应用程序的事实上的标准。
Spring Security 不仅为应用程序提供身份验证,还提供授权功能。 Spring Security 具有以下特性:
如您所见,Spring Security 在安全领域提供了很多东西。我们主要关注基本身份验证和 OAuth2,以便能够利用其适当的依赖关系。打开您的 build.grade 配置并扩展它:
接下来,我们将定义一些用户角色。我们将定义用户角色以及该角色可以执行的API调用。因此,我们将扮演以下角色:
没有角色(未登录)的用户无法执行任何 API 调用。
我们已经确定了角色的范围,因此我们需要创建适当的类。创建一个名为 security 的新包。我们将创建的第一个类将是代表用户定义的类。创建一个名为 User 的类,并确保它扩展了 org.springframework.security.core.userdetails 包中的 UserDetails 类:
扩展 UserDetails 类提供核心用户信息。出于安全目的,Spring Security 不直接使用实现。它只是用来存储用户的信息,后来被封装成认证实现对象(从org.springframework.security.core.Authentication导入)。
这使得存储与安全无关的用户信息(例如电子邮件地址和电话号码)成为可能。
如您所见,UserDetails 类强制我们重写以下方法:
我们将像这样实现我们的 User 类:
有一些重要的注意事项。我们将 User 类视为一个实体,因此它将存储在数据库中。 @Email 注释告诉框架检查电子邮件以进行验证。 @NotBlank 注释将阻止我们发送无效数据。 @NotBlank 检查值不为空或为空。 Spring首先修剪该值。像这样,不可能通过空格。我们将借此机会提及两个更重要的注释:
构建并运行您的 Spring 应用程序,然后检查表和数据库的结构。您会注意到还有一个名为 user 的表,其结构如下:
为了涵盖 ADMIN 角色,我们必须再引入一个类。在您创建 User 类的同一包中创建一个名为 Admin 的类:
再次运行 your application 并查看 user 表中发生的更改:
如您所见,现在多了一个字段:dtype.
我们也必须实现一个 Member 类,所以我们涵盖了我们的 MEMBER 角色。创建一个 Member 类并确保它是这样实现的:
Member 类与 Admin 类具有相同的实现,但它将在不同角色的上下文中使用。
我们将需要 DTO 来为我们将定义的所有与用户相关的操作实现最大的灵活性。第一个 DTO 将是我们在返回系统中可用用户列表时使用的 DTO。定义一个名为 UserDetailsDTO 的新类:
UserDetailsDTO 是一个简单的数据类,只包含必填字段。如您所见,我们不会返回密码值。为了保存新用户,我们将定义另一个名为 UserDTO 的数据类:
我们将在系统中创建新用户时使用它。将仅提供这四个字段。其他字段将自动填充,或使用默认值。
为了能够将用户保存在数据库中,我们需要一个存储库。创建 UserRepository:
为了能够通过用户名(在我们的例子中是电子邮件地址)定位用户,我们必须有一个 findOneByEmail() 方法。
为了能够获取用户列表或创建新用户,我们需要为用户相关需求定义 API 调用。我们将有以下调用:
所有与用户相关的操作都将在 UserService 类中执行:
userService 将执行所有 CRUD 操作。为了触发它们中的任何一个,我们需要最终将 UserService 与 UserController 连接起来,这将定义我们计划的所有 API 调用:
到目前为止,我们已经准备好所有与用户相关的东西,但还没有任何东西是安全的。如果您运行您的应用程序,您将能够执行任何 API 调用而无需任何身份验证。
为了能够对用户进行身份验证和授权,我们将添加基本身份验证实现。默认情况下,Spring 会将 /login 处理为一个网页,这是我们的 REST API 不希望的。在 security 包中创建一个新类并将其命名为 WebSecurityEntryPoint。
此类必须实现 AuthenticationEntryPoint 接口,其目的是启动身份验证方案。实现将如下所示:
那么,commence() 方法有什么作用呢?顾名思义,它启动了一个身份验证方案。 Spring Security 通过使用 Entry Point 的概念自动触发身份验证过程来处理身份验证。入口点是配置的必需部分,可以注入。我们的入口点实现将在触发时简单地返回 401。
我们还需要一个身份验证成功处理程序。该类将负责处理身份验证结果。创建一个名为 WebSecurityAuthSuccessHandler 的新类,并确保它扩展了 SimpleUrlAuthenticationSuccessHandler 类:
我们定义这样一个事实,即成功验证所需的响应应该是 200 OK。我们将注入身份验证成功处理程序实现来替换默认值。默认会执行重定向,但由于我们正在制作一个 REST API,我们不需要它,只需要成功响应。
让我们把事情联系在一起并配置 Spring Security!要配置 Spring Security,我们需要创建一个扩展 WebSecurityConfigurerAdapter 的 Spring 配置类。创建一个名为 WebSecurityConfiguration 的新类:
让我们解释一下我们刚刚做了什么。如果从类实现的底部看,您会注意到以下方法:
通过使用这种选民组合,我们将能够对用户进行身份验证和授权。在您尝试我们实现的代码之前,您需要在数据库中填充一些用户。我们需要至少一个具有 ADMIN 角色的用户和至少一个具有 MEMBER 角色的用户。为此,我们将创建一个测试,该测试将实例化用户并将其插入数据库。我们不会详细介绍此测试,因为我们将在 第 9 章中介绍测试< /a>,测试。
找到你的项目的测试目录(/src/test)并在名为的测试包(src/test/kotlin/com/journaler/api)下创建一个测试类SecurityInitializationTest 具有以下实现:
运行您的测试(右键单击 SecurityInitializationTest.kt 并单击 Run 'SecurityInitializationTest' 选项)。初始化 Spring Boot 并执行测试需要一些时间,如下图所示:
完成后,检查数据库的内容:
如您所见,插入了两个用户。使用测试代码中的 username 和 password 进行身份验证。让我们尝试登录。打开 Postman 并进行身份验证:
慢慢来,使用我们项目中引入的 Spring Security 进行 API 调用。
Spring Security 是巨大的!使用 Spring Security,可以实现比我们刚才介绍的更多的事情。让我们重点介绍一些出色的 Spring Security 特性。
例如,您可以定义自己的授权提供程序和授权规则,或者,例如,只需几行代码即可轻松支持 LDAP 或 OpenID 身份验证。
使用 Spring Security,您可以对密码进行编码和验证。类必须实现 PasswordEncoder 接口:
这些是最常用的实现:
您可能已经注意到,在我们的示例中,我们使用了 BCryptPasswordEncoder 实现。
需要注意的是,可以使用注释来执行方法级别的安全性,例如:
通过本章介绍的示例,我们刚刚接触了 Spring Security 的基础知识。不要害怕,因为它需要你时间来掌握它。 Spring Security 需要一些时间来学习和发现它的所有可能性。请耐心等待,尽可能多地编写代码!阅读 Spring Security 相关的文献,不要着急。您将成为 Spring Security 大师!
安全的应用程序是必须的! Spring 为我们提供了完美的工具。 Spring Security 作为一个高度可定制的身份验证和访问控制框架,是实现这一目标的绝佳选择。我们演示了如何进行基本到高级的安全设置,以及如何防止未经授权使用我们的 API 调用。在下一章中,我们将向您展示 Spring Cloud 以及如何实现分布式系统中的一些常见需求。