第2章 Spring Security 的环境设置与基础配置(2024 最新版)(上)https://developer.aliyun.com/article/1487141
2.2.3 拓展案例 1:数据库用户存储
在这个案例中,我们将展示如何在 Spring Boot 应用中使用数据库进行用户认证,这是实际生产环境中非常常见的场景。
案例 Demo
我们将创建一个简单的 Spring Boot 应用,其中用户信息存储在数据库中,并用于认证。
步骤 1:添加依赖
- 在
pom.xml
文件中添加spring-boot-starter-data-jpa
和数据库依赖(这里我们使用 H2 数据库作为示例)。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency>
步骤 2:配置数据源
- 在
application.properties
文件中配置 H2 数据库。
spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.h2.console.enabled=true
步骤 3:创建用户实体和仓库
- 创建用户实体
User
。
package com.example.demo; import javax.persistence.Entity; import javax.persistence.Id; @Entity public class User { @Id private String username; private String password; private String role; // Getters and Setters }
- 创建用户仓库接口
UserRepository
。
package com.example.demo; import org.springframework.data.jpa.repository.JpaRepository; public interface UserRepository extends JpaRepository<User, String> { }
步骤 4:实现 UserDetailsService
- 创建服务
CustomUserDetailsService
实现UserDetailsService
。
package com.example.demo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @Service public class CustomUserDetailsService implements UserDetailsService { @Autowired private UserRepository userRepository; @Autowired private PasswordEncoder passwordEncoder; @Override public User loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findById(username) .orElseThrow(() -> new UsernameNotFoundException("User not found")); return new User(user.getUsername(), passwordEncoder.encode(user.getPassword()), Collections.singletonList(new SimpleGrantedAuthority(user.getRole()))); } }
步骤 5:配置 Spring Security
- 修改
SecurityConfig
类,使用自定义的UserDetailsService
和密码编码器。
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.context.annotation.Bean; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @Autowired private CustomUserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }
步骤 6:运行和测试
- 启动 Spring Boot 应用。
- 通过 H2 Console 或其他方式添加用户数据到数据库。
- 尝试登录,验证用户认证是否工作正常。
通过此案例,你可以学习到如何在 Spring Boot 应用中结合数据库进行用户认证。这为你提供了一个更接近真实世界应用的安全配置方案。
2.2.4 拓展案例 2:OAuth2 集成
在这个案例中,我们将在 Spring Boot 应用中集成 OAuth2,允许用户使用第三方服务(如 Google, Facebook)进行登录,这是现代应用中常见的一种用户认证方式。
案例 Demo
我们的目标是创建一个 Spring Boot 应用,其中用户可以通过 Google 账户登录。
步骤 1:添加 OAuth2 客户端依赖
- 在
pom.xml
中添加spring-boot-starter-oauth2-client
依赖。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> </dependency>
步骤 2:配置 OAuth2 客户端
- 在
application.properties
或application.yml
文件中配置 Google OAuth2 客户端信息。
- 您需要在 Google Cloud Console 中创建 OAuth2.0 客户端 ID,以获取客户端 ID 和秘密。
步骤 3:安全配置
- 修改
SecurityConfig
类,以支持 OAuth2 登录。
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .oauth2Login(); }
步骤 4:创建控制器来处理登录后的操作
- 创建一个控制器来展示用户信息。
import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class UserController { @GetMapping("/user") public String user(@AuthenticationPrincipal OAuth2User principal) { return "Welcome, " + principal.getAttribute("name"); } }
步骤 5:运行和测试
- 启动 Spring Boot 应用。
- 访问
http://localhost:8080/user
。 - 应用将重定向到 Google 的登录页面。使用 Google 账户登录。
- 登录成功后,应显示欢迎消息和用户信息。
通过这个案例,您可以了解到如何在 Spring Boot 应用中实现 OAuth2 集成,使用户可以通过第三方服务进行身份验证,从而提供更加流畅和安全的用户体验。这种认证方式广泛应用于现代网页和移动应用中。
2.3 测试你的配置
在集成了 Spring Security 后,测试你的配置是确保一切按预期工作的重要步骤。这不仅关乎安全性,也关乎功能的正确实现。
2.3.1 基础知识详解
在集成了 Spring Security 后,测试你的配置是确保一切按预期工作的重要步骤。这部分不仅关乎安全性,也涉及到功能性的正确实现。
重要的测试概念
- 安全性测试:
- 确认认证(Authentication)和授权(Authorization)机制按预期工作。
- 验证不同用户角色的访问权限是否正确实现。
- 端点测试:
- 测试不同的 API 端点以确保安全配置正确,例如,某些端点应仅对认证用户开放。
- 测试类型:
- 单元测试: 测试单个方法或类的功能。
- 集成测试: 测试多个组件协同工作的情况。
- 端到端测试: 测试整个应用程序的工作流程。
- 测试工具:
- JUnit: Java 程序员最常用的单元测试框架。
- MockMvc: 用于模拟 MVC 测试,可以模拟发送 HTTP 请求并验证结果。
- Spring Security Test: 提供了一系列用于测试 Spring Security 配置的工具。
如何进行有效的安全性测试
- 模拟认证用户: 使用测试工具模拟不同角色的用户,以测试他们的访问权限。
- 测试受保护的资源: 验证受保护的资源(如 API 端点)是否仅对具有适当权限的用户开放。
- 测试登录流程: 确保登录流程按预期工作,包括错误处理。
- CSRF 防护测试: 如果应用启用了 CSRF 防护,应进行相应的测试以确保其有效性。
通过这些测试,你可以保证你的 Spring Security 配置既安全又高效,为用户提供了必要的保护,同时不会干扰应用程序的正常功能。测试是任何安全配置不可或缺的一部分,它确保了安全措施的有效性和应用的健壮性。
2.3.2 主要案例:测试基本的安全配置
在这个案例中,我们将通过一个实际的示例来测试在 Spring Boot 应用中集成的基本 Spring Security 配置。
案例 Demo
假设我们的 Spring Boot 应用有两个主要端点:一个公开的主页 (/
) 和一个受保护的用户页面 (/user
)。我们将编写测试来验证安全配置是否按预期工作。
步骤 1:添加测试依赖
- 在
pom.xml
文件中添加以下依赖,以支持测试:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
步骤 2:编写测试类
- 创建一个测试类
WebSecurityConfigTest
。
package com.example.demo; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @SpringBootTest @AutoConfigureMockMvc public class WebSecurityConfigTest { @Autowired private MockMvc mockMvc; @Test public void accessPublic() throws Exception { mockMvc.perform(get("/")) .andExpect(status().isOk()); } @Test public void accessPrivateUnauthenticated() throws Exception { mockMvc.perform(get("/user")) .andExpect(status().isUnauthorized()); } }
- 在这里,我们使用
MockMvc
来模拟发送 HTTP 请求到不同的端点,并验证响应的状态码。我们期望公开页面返回200 OK
状态,而未经认证的访问受保护的/user
端点应返回401 Unauthorized
状态。
步骤 3:运行测试
- 在 IDE 中运行测试类或使用 Maven/Gradle 命令行工具来执行测试。
- 检查测试结果,确认安全配置是否按预期工作。
通过这个案例,你可以验证你的 Spring Security 配置是否正确实现了基本的认证和授权。这种测试是确保应用安全性的重要步骤,能帮助你捕获潜在的安全问题和配置错误。
2.3.3 ### 拓展案例 1:测试数据库用户存储
在这个案例中,我们将测试 Spring Boot 应用中使用数据库进行用户认证的配置。假设我们的应用使用数据库来存储用户信息,并基于这些信息进行认证。
案例 Demo
假设我们已经有一个集成了数据库用户存储的 Spring Boot 应用,现在我们需要编写测试来验证用户认证功能。
步骤 1:配置测试数据库
- 在
src/test/resources
目录下创建一个application.properties
文件,配置用于测试的数据库信息(使用 H2 数据库作为示例)。
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1 spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.h2.console.enabled=true
步骤 2:添加测试依赖
- 确保在
pom.xml
中已经添加了spring-boot-starter-test
和h2
数据库的依赖。
<!-- Test dependencies --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>test</scope> </dependency>
步骤 3:编写测试类
- 创建一个测试类
UserAuthenticationTest
。
package com.example.demo; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @SpringBootTest @AutoConfigureMockMvc public class UserAuthenticationTest { @Autowired private MockMvc mockMvc; @Autowired private UserRepository userRepository; @Autowired private PasswordEncoder passwordEncoder; @BeforeEach public void setup() { User user = new User(); user.setUsername("testuser"); user.setPassword(passwordEncoder.encode("password")); user.setRole("USER"); userRepository.save(user); } @Test public void authenticateWithValidUser() throws Exception { mockMvc.perform(post("/login") .param("username", "testuser") .param("password", "password")) .andExpect(status().isOk()); } @Test public void authenticateWithInvalidUser() throws Exception { mockMvc.perform(post("/login") .param("username", "invaliduser") .param("password", "password")) .andExpect(status().isUnauthorized()); } }
- 在这里,我们使用
MockMvc
来模拟登录请求,并验证不同用户(有效和无效)的认证结果。
步骤 4:运行测试
- 在 IDE 中运行测试类或使用 Maven/Gradle 命令行工具来执行测试。
- 检查测试结果,确认数据库用户存储和认证是否按预期工作。
通过这个案例,你可以确保你的 Spring Boot 应用中的用户认证机制(基于数据库存储)按预期运行,从而提高应用的安全性和可靠性。
2.3.4 拓展案例 2:测试 OAuth2 集成
在这个案例中,我们将演示如何测试 Spring Boot 应用中的 OAuth2 集成,确保第三方登录(如 Google OAuth2)按预期工作。
案例 Demo
假设我们的 Spring Boot 应用已经集成了 Google OAuth2 登录。我们需要编写测试来验证 OAuth2 流程。
步骤 1:添加测试依赖
- 确保在
pom.xml
中添加了spring-boot-starter-test
依赖。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
步骤 2:配置 OAuth2 测试
- 在测试配置中(
src/test/resources/application.properties
),添加用于测试的 OAuth2 配置。
spring.security.oauth2.client.registration.google.client-id=test-client-id spring.security.oauth2.client.registration.google.client-secret=test-client-secret
步骤 3:编写测试类
- 创建一个测试类
OAuth2LoginTest
。
package com.example.demo; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.security.test.context.support.WithMockUser; import org.springframework.test.web.servlet.MockMvc; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @SpringBootTest @AutoConfigureMockMvc public class OAuth2LoginTest { @Autowired private MockMvc mockMvc; @Test @WithMockUser public void requestProtectedUrlWithUser() throws Exception { mockMvc.perform(get("/user")) .andExpect(status().isOk()); } @Test public void requestProtectedUrlWithoutUser() throws Exception { mockMvc.perform(get("/user")) .andExpect(status().is3xxRedirection()) .andExpect(redirectedUrlPattern("**/oauth2/authorization/google")); } }
- 这里我们使用
WithMockUser
来模拟一个已认证的用户,以测试受保护的 URL 访问。同时,我们测试未认证用户访问受保护 URL 时的重定向行为。
步骤 4:运行测试
- 在 IDE 中运行测试类或使用 Maven/Gradle 命令行工具来执行测试。
- 检查测试结果,确认 OAuth2 集成是否按预期工作。
通过这个案例,你可以确保你的应用中的 OAuth2 集成正确实现了第三方登录流程,提供了有效的用户认证机制。这对于提供一个安全、便捷的用户登录体验至关重要。