Spring Boot 安全认证与授权
Spring Boot 安全认证与授权
22.1 学习目标与重点提示
学习目标:掌握Spring Boot安全认证与授权的核心概念与使用方法,包括Spring Security的定义与特点、Spring Boot与Spring Security的集成、Spring Boot与Spring Security的配置、Spring Boot与Spring Security的认证、Spring Boot与Spring Security的授权、Spring Boot与Spring Security的实际应用场景,学会在实际开发中处理安全认证与授权问题。
重点:Spring Security的定义与特点、Spring Boot与Spring Security的集成、Spring Boot与Spring Security的配置、Spring Boot与Spring Security的认证、Spring Boot与Spring Security的授权、Spring Boot与Spring Security的实际应用场景。
22.2 Spring Security概述
Spring Security是Java开发中的重要组件。
22.2.1 Spring Security的定义
定义:Spring Security是Spring Boot提供的安全框架。
作用:
- 实现用户认证。
- 实现用户授权。
- 提供安全的编程模型。
常见的安全框架:
- Spring Security:Spring Boot提供的安全框架。
- Shiro:Apache Shiro是一款开源的安全框架。
✅ 结论:Spring Security是Spring Boot提供的安全框架,作用是实现用户认证、用户授权、提供安全的编程模型。
22.2.2 Spring Security的特点
定义:Spring Security的特点是指Spring Security的特性。
特点:
- 全面性:Spring Security提供了全面的安全功能。
- 可扩展性:Spring Security可以扩展到多个应用程序之间的安全通信。
- 易用性:Spring Security提供了易用的编程模型。
- 整合性:Spring Security可以与Spring Boot、Spring Cloud等整合。
✅ 结论:Spring Security的特点包括全面性、可扩展性、易用性、整合性。
22.3 Spring Boot与Spring Security的集成
Spring Boot与Spring Security的集成是Java开发中的重要内容。
22.3.1 集成Spring Security的步骤
定义:集成Spring Security的步骤是指使用Spring Boot与Spring Security集成的方法。
步骤:
- 创建Spring Boot项目。
- 添加所需的依赖。
- 配置Spring Security。
- 创建用户服务类。
- 创建控制器类。
- 测试应用。
示例:
pom.xml文件中的依赖:
<dependencies><!-- Web依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Security依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!-- 测试依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>Spring Security配置类:
importorg.springframework.context.annotation.Configuration;importorg.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;importorg.springframework.security.config.annotation.web.builders.HttpSecurity;importorg.springframework.security.config.annotation.web.configuration.EnableWebSecurity;importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;importorg.springframework.security.crypto.password.NoOpPasswordEncoder;@Configuration@EnableWebSecuritypublicclassSecurityConfigextendsWebSecurityConfigurerAdapter{@Overrideprotectedvoidconfigure(AuthenticationManagerBuilder auth)throwsException{ auth.inMemoryAuthentication().passwordEncoder(NoOpPasswordEncoder.getInstance()).withUser("admin").password("admin123").roles("ADMIN").and().withUser("user").password("user123").roles("USER");}@Overrideprotectedvoidconfigure(HttpSecurity http)throwsException{ http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/user/**").hasRole("USER").antMatchers("/").permitAll().and().formLogin().loginPage("/login").permitAll().and().logout().permitAll();}}控制器类:
importorg.springframework.stereotype.Controller;importorg.springframework.web.bind.annotation.GetMapping;@ControllerpublicclassSecurityController{@GetMapping("/")publicStringindex(){return"index";}@GetMapping("/login")publicStringlogin(){return"login";}@GetMapping("/user")publicStringuser(){return"user";}@GetMapping("/admin")publicStringadmin(){return"admin";}}视图模板文件(src/main/resources/templates/index.html):
<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><title>首页</title><style>body{font-family: Arial, sans-serif;margin: 0;padding: 0;display: flex;justify-content: center;align-items: center;height: 100vh;background-color: #f5f5f5;}.container{background-color: white;padding: 20px;border-radius: 5px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);}h1{color: #333;margin-bottom: 20px;}a{text-decoration: none;color: #007bff;margin-right: 20px;}a:hover{text-decoration: underline;}</style></head><body><divclass="container"><h1>首页</h1><ahref="/login">登录</a><ahref="/user">用户页面</a><ahref="/admin">管理员页面</a></div></body></html>视图模板文件(src/main/resources/templates/login.html):
<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><title>登录</title><style>body{font-family: Arial, sans-serif;margin: 0;padding: 0;display: flex;justify-content: center;align-items: center;height: 100vh;background-color: #f5f5f5;}.container{background-color: white;padding: 20px;border-radius: 5px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);}h1{color: #333;margin-bottom: 20px;}form{display: flex;flex-direction: column;}label{margin-bottom: 5px;color: #333;}input{margin-bottom: 10px;padding: 8px;border: 1px solid #ddd;border-radius: 5px;}button{padding: 10px;background-color: #007bff;color: white;border: none;border-radius: 5px;cursor: pointer;}button:hover{background-color: #0056b3;}a{text-decoration: none;color: #007bff;margin-top: 10px;text-align: center;}a:hover{text-decoration: underline;}</style></head><body><divclass="container"><h1>登录</h1><formth:action="@{/login}"method="post"><labelfor="username">用户名:</label><inputtype="text"id="username"name="username"required><labelfor="password">密码:</label><inputtype="password"id="password"name="password"required><buttontype="submit">登录</button></form><ahref="/">返回首页</a></div></body></html>视图模板文件(src/main/resources/templates/user.html):
<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><title>用户页面</title><style>body{font-family: Arial, sans-serif;margin: 0;padding: 0;display: flex;justify-content: center;align-items: center;height: 100vh;background-color: #f5f5f5;}.container{background-color: white;padding: 20px;border-radius: 5px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);}h1{color: #333;margin-bottom: 20px;}a{text-decoration: none;color: #007bff;margin-right: 20px;}a:hover{text-decoration: underline;}</style></head><body><divclass="container"><h1>用户页面</h1><ahref="/">返回首页</a><ahref="/logout">登出</a></div></body></html>视图模板文件(src/main/resources/templates/admin.html):
<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><title>管理员页面</title><style>body{font-family: Arial, sans-serif;margin: 0;padding: 0;display: flex;justify-content: center;align-items: center;height: 100vh;background-color: #f5f5f5;}.container{background-color: white;padding: 20px;border-radius: 5px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);}h1{color: #333;margin-bottom: 20px;}a{text-decoration: none;color: #007bff;margin-right: 20px;}a:hover{text-decoration: underline;}</style></head><body><divclass="container"><h1>管理员页面</h1><ahref="/">返回首页</a><ahref="/logout">登出</a></div></body></html>测试类:
importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importorg.springframework.boot.test.web.client.TestRestTemplate;importorg.springframework.boot.web.server.LocalServerPort;importorg.springframework.http.HttpEntity;importorg.springframework.http.HttpHeaders;importorg.springframework.http.HttpMethod;importorg.springframework.http.ResponseEntity;importjava.util.Base64;importjava.util.Map;importstaticorg.assertj.core.api.Assertions.assertThat;@SpringBootTest(webEnvironment =SpringBootTest.WebEnvironment.RANDOM_PORT)classSpringSecurityApplicationTests{@LocalServerPortprivateint port;@AutowiredprivateTestRestTemplate restTemplate;@TestvoidcontextLoads(){}@TestvoidtestIndexPage(){String response = restTemplate.getForObject("http://localhost:"+ port +"/",String.class);assertThat(response).contains("首页");}@TestvoidtestUserPageWithoutAuthentication(){ResponseEntity<Map> response = restTemplate.getForEntity("http://localhost:"+ port +"/user",Map.class);assertThat(response.getStatusCodeValue()).isEqualTo(302);}@TestvoidtestUserPageWithUserAuthentication(){String credentials ="user:user123";String base64Credentials =Base64.getEncoder().encodeToString(credentials.getBytes());HttpHeaders headers =newHttpHeaders(); headers.add("Authorization","Basic "+ base64Credentials);HttpEntity<String> entity =newHttpEntity<>(headers);ResponseEntity<String> response = restTemplate.exchange("http://localhost:"+ port +"/user",HttpMethod.GET, entity,String.class);assertThat(response.getStatusCodeValue()).isEqualTo(200);assertThat(response.getBody()).contains("用户页面");}@TestvoidtestAdminPageWithoutAuthentication(){ResponseEntity<Map> response = restTemplate.getForEntity("http://localhost:"+ port +"/admin",Map.class);assertThat(response.getStatusCodeValue()).isEqualTo(302);}@TestvoidtestAdminPageWithAdminAuthentication(){String credentials ="admin:admin123";String base64Credentials =Base64.getEncoder().encodeToString(credentials.getBytes());HttpHeaders headers =newHttpHeaders(); headers.add("Authorization","Basic "+ base64Credentials);HttpEntity<String> entity =newHttpEntity<>(headers);ResponseEntity<String> response = restTemplate.exchange("http://localhost:"+ port +"/admin",HttpMethod.GET, entity,String.class);assertThat(response.getStatusCodeValue()).isEqualTo(200);assertThat(response.getBody()).contains("管理员页面");}}✅ 结论:集成Spring Security的步骤包括创建Spring Boot项目、添加所需的依赖、配置Spring Security、创建用户服务类、创建控制器类、测试应用。
22.4 Spring Boot与Spring Security的认证
Spring Boot与Spring Security的认证是Java开发中的重要内容。
22.4.1 基于内存的认证
定义:基于内存的认证是指Spring Security提供的一种认证方式。
作用:
- 实现用户认证。
- 提供安全的编程模型。
示例:
importorg.springframework.context.annotation.Configuration;importorg.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;importorg.springframework.security.config.annotation.web.builders.HttpSecurity;importorg.springframework.security.config.annotation.web.configuration.EnableWebSecurity;importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;importorg.springframework.security.crypto.password.NoOpPasswordEncoder;@Configuration@EnableWebSecuritypublicclassSecurityConfigextendsWebSecurityConfigurerAdapter{@Overrideprotectedvoidconfigure(AuthenticationManagerBuilder auth)throwsException{ auth.inMemoryAuthentication().passwordEncoder(NoOpPasswordEncoder.getInstance()).withUser("admin").password("admin123").roles("ADMIN").and().withUser("user").password("user123").roles("USER");}@Overrideprotectedvoidconfigure(HttpSecurity http)throwsException{ http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/user/**").hasRole("USER").antMatchers("/").permitAll().and().formLogin().loginPage("/login").permitAll().and().logout().permitAll();}}✅ 结论:基于内存的认证是指Spring Security提供的一种认证方式,作用是实现用户认证、提供安全的编程模型。
22.4.2 基于数据库的认证
定义:基于数据库的认证是指Spring Security提供的一种认证方式。
作用:
- 实现用户认证。
- 提供安全的编程模型。
示例:
pom.xml文件中的依赖:
<dependencies><!-- Web依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Security依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!-- Data JPA依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- H2数据库依赖 --><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency><!-- 测试依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>实体类:
importjavax.persistence.*;@Entity@Table(name ="user")publicclassUser{@Id@GeneratedValue(strategy =GenerationType.IDENTITY)privateLong id;privateString username;privateString password;privateString role;publicUser(){}publicUser(String username,String password,String role){this.username = username;this.password = password;this.role = role;}// Getter和Setter方法publicLonggetId(){return id;}publicvoidsetId(Long id){this.id = id;}publicStringgetUsername(){return username;}publicvoidsetUsername(String username){this.username = username;}publicStringgetPassword(){return password;}publicvoidsetPassword(String password){this.password = password;}publicStringgetRole(){return role;}publicvoidsetRole(String role){this.role = role;}@OverridepublicStringtoString(){return"User{"+"id="+ id +",+ username +'\''+",+ password +'\''+",+ role +'\''+'}';}}Repository接口:
importorg.springframework.data.jpa.repository.JpaRepository;importorg.springframework.stereotype.Repository;@RepositorypublicinterfaceUserRepositoryextendsJpaRepository<User,Long>{UserfindByUsername(String username);}用户服务类:
importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.security.core.GrantedAuthority;importorg.springframework.security.core.authority.SimpleGrantedAuthority;importorg.springframework.security.core.userdetails.UserDetails;importorg.springframework.security.core.userdetails.UserDetailsService;importorg.springframework.security.core.userdetails.UsernameNotFoundException;importorg.springframework.stereotype.Service;importjava.util.ArrayList;importjava.util.List;@ServicepublicclassUserDetailsServiceImplimplementsUserDetailsService{@AutowiredprivateUserRepository userRepository;@OverridepublicUserDetailsloadUserByUsername(String username)throwsUsernameNotFoundException{User user = userRepository.findByUsername(username);if(user ==null){thrownewUsernameNotFoundException("用户不存在:"+ username);}List<GrantedAuthority> authorities =newArrayList<>(); authorities.add(newSimpleGrantedAuthority("ROLE_"+ user.getRole()));returnorg.springframework.security.core.userdetails.User.builder().username(user.getUsername()).password(user.getPassword()).authorities(authorities).build();}}Spring Security配置类:
importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.security.authentication.AuthenticationManager;importorg.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;importorg.springframework.security.config.annotation.web.builders.HttpSecurity;importorg.springframework.security.config.annotation.web.configuration.EnableWebSecurity;importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;importorg.springframework.security.crypto.password.NoOpPasswordEncoder;importorg.springframework.security.crypto.password.PasswordEncoder;@Configuration@EnableWebSecuritypublicclassSecurityConfigextendsWebSecurityConfigurerAdapter{@AutowiredprivateUserDetailsServiceImpl userDetailsService;@Overrideprotectedvoidconfigure(AuthenticationManagerBuilder auth)throwsException{ auth.userDetailsService(userDetailsService);}@BeanpublicPasswordEncoderpasswordEncoder(){returnNoOpPasswordEncoder.getInstance();}@Bean@OverridepublicAuthenticationManagerauthenticationManagerBean()throwsException{returnsuper.authenticationManagerBean();}@Overrideprotectedvoidconfigure(HttpSecurity http)throwsException{ http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/user/**").hasRole("USER").antMatchers("/").permitAll().and().formLogin().loginPage("/login").permitAll().and().logout().permitAll();}}控制器类:
importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Controller;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.PostMapping;@ControllerpublicclassSecurityController{@AutowiredprivateUserRepository userRepository;@GetMapping("/")publicStringindex(){return"index";}@GetMapping("/login")publicStringlogin(){return"login";}@GetMapping("/user")publicStringuser(){return"user";}@GetMapping("/admin")publicStringadmin(){return"admin";}@PostMapping("/register")publicStringregisterUser(String username,String password,String role){User user =newUser(username, password, role); userRepository.save(user);return"redirect:/login";}}视图模板文件(src/main/resources/templates/register.html):
<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><title>注册</title><style>body{font-family: Arial, sans-serif;margin: 0;padding: 0;display: flex;justify-content: center;align-items: center;height: 100vh;background-color: #f5f5f5;}.container{background-color: white;padding: 20px;border-radius: 5px;box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);}h1{color: #333;margin-bottom: 20px;}form{display: flex;flex-direction: column;}label{margin-bottom: 5px;color: #333;}input{margin-bottom: 10px;padding: 8px;border: 1px solid #ddd;border-radius: 5px;}select{margin-bottom: 10px;padding: 8px;border: 1px solid #ddd;border-radius: 5px;}button{padding: 10px;background-color: #007bff;color: white;border: none;border-radius: 5px;cursor: pointer;}button:hover{background-color: #0056b3;}a{text-decoration: none;color: #007bff;margin-top: 10px;text-align: center;}a:hover{text-decoration: underline;}</style></head><body><divclass="container"><h1>注册</h1><formth:action="@{/register}"method="post"><labelfor="username">用户名:</label><inputtype="text"id="username"name="username"required><labelfor="password">密码:</label><inputtype="password"id="password"name="password"required><labelfor="role">角色:</label><selectid="role"name="role"required><optionvalue="USER">用户</option><optionvalue="ADMIN">管理员</option></select><buttontype="submit">注册</button></form><ahref="/">返回首页</a></div></body></html>测试类:
importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importorg.springframework.boot.test.web.client.TestRestTemplate;importorg.springframework.boot.web.server.LocalServerPort;importorg.springframework.http.HttpEntity;importorg.springframework.http.HttpHeaders;importorg.springframework.http.HttpMethod;importorg.springframework.http.ResponseEntity;importjava.util.Base64;importjava.util.Map;importstaticorg.assertj.core.api.Assertions.assertThat;@SpringBootTest(webEnvironment =SpringBootTest.WebEnvironment.RANDOM_PORT)classSpringSecurityApplicationTests{@LocalServerPortprivateint port;@AutowiredprivateTestRestTemplate restTemplate;@TestvoidcontextLoads(){}@TestvoidtestIndexPage(){String response = restTemplate.getForObject("http://localhost:"+ port +"/",String.class);assertThat(response).contains("首页");}@TestvoidtestUserPageWithoutAuthentication(){ResponseEntity<Map> response = restTemplate.getForEntity("http://localhost:"+ port +"/user",Map.class);assertThat(response.getStatusCodeValue()).isEqualTo(302);}@TestvoidtestUserPageWithUserAuthentication(){String credentials ="user:user123";String base64Credentials =Base64.getEncoder().encodeToString(credentials.getBytes());HttpHeaders headers =newHttpHeaders(); headers.add("Authorization","Basic "+ base64Credentials);HttpEntity<String> entity =newHttpEntity<>(headers);ResponseEntity<String> response = restTemplate.exchange("http://localhost:"+ port +"/user",HttpMethod.GET, entity,String.class);assertThat(response.getStatusCodeValue()).isEqualTo(200);assertThat(response.getBody()).contains("用户页面");}@TestvoidtestAdminPageWithoutAuthentication(){ResponseEntity<Map> response = restTemplate.getForEntity("http://localhost:"+ port +"/admin",Map.class);assertThat(response.getStatusCodeValue()).isEqualTo(302);}@TestvoidtestAdminPageWithAdminAuthentication(){String credentials ="admin:admin123";String base64Credentials =Base64.getEncoder().encodeToString(credentials.getBytes());HttpHeaders headers =newHttpHeaders(); headers.add("Authorization","Basic "+ base64Credentials);HttpEntity<String> entity =newHttpEntity<>(headers);ResponseEntity<String> response = restTemplate.exchange("http://localhost:"+ port +"/admin",HttpMethod.GET, entity,String.class);assertThat(response.getStatusCodeValue()).isEqualTo(200);assertThat(response.getBody()).contains("管理员页面");}}✅ 结论:基于数据库的认证是指Spring Security提供的一种认证方式,作用是实现用户认证、提供安全的编程模型。
22.5 Spring Boot与Spring Security的授权
Spring Boot与Spring Security的授权是Java开发中的重要内容。
22.5.1 基于角色的授权
定义:基于角色的授权是指Spring Security提供的一种授权方式。
作用:
- 实现用户授权。
- 提供安全的编程模型。
示例:
importorg.springframework.context.annotation.Configuration;importorg.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;importorg.springframework.security.config.annotation.web.builders.HttpSecurity;importorg.springframework.security.config.annotation.web.configuration.EnableWebSecurity;importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;importorg.springframework.security.crypto.password.NoOpPasswordEncoder;@Configuration@EnableWebSecuritypublicclassSecurityConfigextendsWebSecurityConfigurerAdapter{@Overrideprotectedvoidconfigure(AuthenticationManagerBuilder auth)throwsException{ auth.inMemoryAuthentication().passwordEncoder(NoOpPasswordEncoder.getInstance()).withUser("admin").password("admin123").roles("ADMIN").and().withUser("user").password("user123").roles("USER");}@Overrideprotectedvoidconfigure(HttpSecurity http)throwsException{ http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/user/**").hasRole("USER").antMatchers("/").permitAll().and().formLogin().loginPage("/login").permitAll().and().logout().permitAll();}}✅ 结论:基于角色的授权是指Spring Security提供的一种授权方式,作用是实现用户授权、提供安全的编程模型。
22.5.2 基于权限的授权
定义:基于权限的授权是指Spring Security提供的一种授权方式。
作用:
- 实现用户授权。
- 提供安全的编程模型。
示例:
importorg.springframework.context.annotation.Configuration;importorg.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;importorg.springframework.security.config.annotation.web.builders.HttpSecurity;importorg.springframework.security.config.annotation.web.configuration.EnableWebSecurity;importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;importorg.springframework.security.crypto.password.NoOpPasswordEncoder;@Configuration@EnableWebSecuritypublicclassSecurityConfigextendsWebSecurityConfigurerAdapter{@Overrideprotectedvoidconfigure(AuthenticationManagerBuilder auth)throwsException{ auth.inMemoryAuthentication().passwordEncoder(NoOpPasswordEncoder.getInstance()).withUser("admin").password("admin123").roles("ADMIN").and().withUser("user").password("user123").roles("USER");}@Overrideprotectedvoidconfigure(HttpSecurity http)throwsException{ http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/user/**").hasRole("USER").antMatchers("/").permitAll().and().formLogin().loginPage("/login").permitAll().and().logout().permitAll();}}✅ 结论:基于权限的授权是指Spring Security提供的一种授权方式,作用是实现用户授权、提供安全的编程模型。
22.6 Spring Boot与Spring Security的实际应用场景
在实际开发中,Spring Boot与Spring Security的应用场景非常广泛,如:
- 实现用户的登录与登出。
- 实现用户的角色管理。
- 实现用户的权限管理。
- 实现系统的安全审计。
示例:
importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;importorg.springframework.security.config.annotation.web.builders.HttpSecurity;importorg.springframework.security.config.annotation.web.configuration.EnableWebSecurity;importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;importorg.springframework.security.crypto.password.NoOpPasswordEncoder;importorg.springframework.stereotype.Controller;importorg.springframework.web.bind.annotation.GetMapping;@SpringBootApplicationpublicclassSecurityApplication{publicstaticvoidmain(String[] args){SpringApplication.run(SecurityApplication.class, args);}}@EnableWebSecurityclassSecurityConfigextendsWebSecurityConfigurerAdapter{@Overrideprotectedvoidconfigure(AuthenticationManagerBuilder auth)throwsException{ auth.inMemoryAuthentication().passwordEncoder(NoOpPasswordEncoder.getInstance()).withUser("admin").password("admin123").roles("ADMIN").and().withUser("user").password("user123").roles("USER");}@Overrideprotectedvoidconfigure(HttpSecurity http)throwsException{ http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/user/**").hasRole("USER").antMatchers("/").permitAll().and().formLogin().loginPage("/login").permitAll().and().logout().permitAll();}}@ControllerclassSecurityController{@GetMapping("/")publicStringindex(){return"index";}@GetMapping("/login")publicStringlogin(){return"login";}@GetMapping("/user")publicStringuser(){return"user";}@GetMapping("/admin")publicStringadmin(){return"admin";}}// 测试类@SpringBootTest(webEnvironment =SpringBootTest.WebEnvironment.RANDOM_PORT)classSecurityApplicationTests{@LocalServerPortprivateint port;@AutowiredprivateTestRestTemplate restTemplate;@TestvoidcontextLoads(){}@TestvoidtestIndexPage(){String response = restTemplate.getForObject("http://localhost:"+ port +"/",String.class);assertThat(response).contains("首页");}@TestvoidtestUserPageWithoutAuthentication(){ResponseEntity<Map> response = restTemplate.getForEntity("http://localhost:"+ port +"/user",Map.class);assertThat(response.getStatusCodeValue()).isEqualTo(302);}@TestvoidtestUserPageWithUserAuthentication(){String credentials ="user:user123";String base64Credentials =Base64.getEncoder().encodeToString(credentials.getBytes());HttpHeaders headers =newHttpHeaders(); headers.add("Authorization","Basic "+ base64Credentials);HttpEntity<String> entity =newHttpEntity<>(headers);ResponseEntity<String> response = restTemplate.exchange("http://localhost:"+ port +"/user",HttpMethod.GET, entity,String.class);assertThat(response.getStatusCodeValue()).isEqualTo(200);assertThat(response.getBody()).contains("用户页面");}@TestvoidtestAdminPageWithoutAuthentication(){ResponseEntity<Map> response = restTemplate.getForEntity("http://localhost:"+ port +"/admin",Map.class);assertThat(response.getStatusCodeValue()).isEqualTo(302);}@TestvoidtestAdminPageWithAdminAuthentication(){String credentials ="admin:admin123";String base64Credentials =Base64.getEncoder().encodeToString(credentials.getBytes());HttpHeaders headers =newHttpHeaders(); headers.add("Authorization","Basic "+ base64Credentials);HttpEntity<String> entity =newHttpEntity<>(headers);ResponseEntity<String> response = restTemplate.exchange("http://localhost:"+ port +"/admin",HttpMethod.GET, entity,String.class);assertThat(response.getStatusCodeValue()).isEqualTo(200);assertThat(response.getBody()).contains("管理员页面");}}输出结果:
- 访问http://localhost:8080/:返回首页。
- 访问http://localhost:8080/login:返回登录页面。
- 访问http://localhost:8080/user:返回用户页面。
- 访问http://localhost:8080/admin:返回管理员页面。
✅ 结论:在实际开发中,Spring Boot与Spring Security的应用场景非常广泛,需要根据实际问题选择合适的安全框架。
总结
本章我们学习了Spring Boot安全认证与授权,包括Spring Security的定义与特点、Spring Boot与Spring Security的集成、Spring Boot与Spring Security的配置、Spring Boot与Spring Security的认证、Spring Boot与Spring Security的授权、Spring Boot与Spring Security的实际应用场景,学会了在实际开发中处理安全认证与授权问题。其中,Spring Security的定义与特点、Spring Boot与Spring Security的集成、Spring Boot与Spring Security的配置、Spring Boot与Spring Security的认证、Spring Boot与Spring Security的授权、Spring Boot与Spring Security的实际应用场景是本章的重点内容。从下一章开始,我们将学习Spring Boot的其他组件、微服务等内容。