Spring Boot 安全认证与授权
Spring Boot 中集成 Spring Security 进行安全认证与授权的完整流程。内容包括 Spring Security 的定义、特点及与 Spring Boot 的集成步骤。详细讲解了基于内存和数据库两种认证方式,以及基于角色和权限的授权策略。通过实际代码示例展示了用户登录、登出、角色管理及权限控制的实现方法,适用于构建安全的 Java Web 应用。

Spring Boot 中集成 Spring Security 进行安全认证与授权的完整流程。内容包括 Spring Security 的定义、特点及与 Spring Boot 的集成步骤。详细讲解了基于内存和数据库两种认证方式,以及基于角色和权限的授权策略。通过实际代码示例展示了用户登录、登出、角色管理及权限控制的实现方法,适用于构建安全的 Java Web 应用。

学习目标:掌握 Spring Boot 安全认证与授权的核心概念与使用方法,包括 Spring Security 的定义与特点、Spring Boot 与 Spring Security 的集成、配置、认证、授权及实际应用场景。
重点:
Spring Security 是 Java 开发中的重要组件。
定义: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 配置类
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.passwordEncoder(NoOpPasswordEncoder.getInstance())
.withUser("admin").password("admin123").roles("ADMIN")
.and()
.withUser("user").password("user123").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasRole("USER")
.antMatchers("/").permitAll()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().permitAll();
}
}
控制器类
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class SecurityController {
@GetMapping("/")
public String index() { return "index"; }
@GetMapping("/login")
public String login() { return "login"; }
@GetMapping("/user")
public String user() { return "user"; }
@GetMapping("/admin")
public String admin() { return "admin"; }
}
视图模板文件(src/main/resources/templates/index.html)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="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>
<div class="container">
<h1>首页</h1>
<a href="/login">登录</a>
<a href="/user">用户页面</a>
<a href="/admin">管理员页面</a>
</div>
</body>
</html>
视图模板文件(src/main/resources/templates/login.html)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="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>
<div class="container">
<h1>登录</h1>
<form th:action="@{/login}" method="post">
<label for="username">用户名:</label>
<input type="text" id="username" name="username" required>
<label for="password">密码:</label>
<input type="password" id="password" name="password" required>
<button type="submit">登录</button>
</form>
<a href="/">返回首页</a>
</div>
</body>
</html>
视图模板文件(src/main/resources/templates/user.html)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="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>
<div class="container">
<h1>用户页面</h1>
<a href="/">返回首页</a>
<a href="/logout">登出</a>
</div>
</body>
</html>
视图模板文件(src/main/resources/templates/admin.html)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="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>
<div class="container">
<h1>管理员页面</h1>
<a href="/">返回首页</a>
<a href="/logout">登出</a>
</div>
</body>
</html>
测试类
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import java.util.Base64;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class SpringSecurityApplicationTests {
@LocalServerPort private int port;
@Autowired private TestRestTemplate restTemplate;
@Test void contextLoads() {}
@Test void testIndexPage() {
String response = restTemplate.getForObject("http://localhost:" + port + "/", String.class);
assertThat(response).contains("首页");
}
@Test void testUserPageWithoutAuthentication() {
ResponseEntity<Map> response = restTemplate.getForEntity("http://localhost:" + port + "/user", Map.class);
assertThat(response.getStatusCodeValue()).isEqualTo(302);
}
@Test void testUserPageWithUserAuthentication() {
String credentials = "user:user123";
String base64Credentials = Base64.getEncoder().encodeToString(credentials.getBytes());
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Credentials);
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange("http://localhost:" + port + "/user", HttpMethod.GET, entity, String.class);
assertThat(response.getStatusCodeValue()).isEqualTo(200);
assertThat(response.getBody()).contains("用户页面");
}
@Test void testAdminPageWithoutAuthentication() {
ResponseEntity<Map> response = restTemplate.getForEntity("http://localhost:" + port + "/admin", Map.class);
assertThat(response.getStatusCodeValue()).isEqualTo(302);
}
@Test void testAdminPageWithAdminAuthentication() {
String credentials = "admin:admin123";
String base64Credentials = Base64.getEncoder().encodeToString(credentials.getBytes());
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Credentials);
HttpEntity<String> entity = new HttpEntity<>(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、创建用户服务类、创建控制器类、测试应用。
定义:基于内存的认证是指 Spring Security 提供的一种认证方式。
作用:
示例:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.passwordEncoder(NoOpPasswordEncoder.getInstance())
.withUser("admin").password("admin123").roles("ADMIN")
.and()
.withUser("user").password("user123").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasRole("USER")
.antMatchers("/").permitAll()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().permitAll();
}
}
小结:基于内存的认证是指 Spring Security 提供的一种认证方式,作用是实现用户认证、提供安全的编程模型。
定义:基于数据库的认证是指 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>
实体类
import javax.persistence.*;
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private String role;
public User() {}
public User(String username, String password, String role) {
this.username = username;
this.password = password;
this.role = role;
}
// Getter 和 Setter 方法
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getRole() { return role; }
public void setRole(String role) { this.role = role; }
@Override
public String toString() {
return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + ", role='" + role + '\'' + '}';
}
}
Repository 接口
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
}
用户服务类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用户不存在:" + username);
}
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_" + user.getRole()));
return org.springframework.security.core.userdetails.User.builder()
.username(user.getUsername())
.password(user.getPassword())
.authorities(authorities)
.build();
}
}
Spring Security 配置类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasRole("USER")
.antMatchers("/").permitAll()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().permitAll();
}
}
控制器类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class SecurityController {
@Autowired
private UserRepository userRepository;
@GetMapping("/")
public String index() { return "index"; }
@GetMapping("/login")
public String login() { return "login"; }
@GetMapping("/user")
public String user() { return "user"; }
@GetMapping("/admin")
public String admin() { return "admin"; }
@PostMapping("/register")
public String registerUser(String username, String password, String role) {
User user = new User(username, password, role);
userRepository.save(user);
return "redirect:/login";
}
}
视图模板文件(src/main/resources/templates/register.html)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="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>
<div class="container">
<h1>注册</h1>
<form th:action="@{/register}" method="post">
<label for="username">用户名:</label>
<input type="text" id="username" name="username" required>
<label for="password">密码:</label>
<input type="password" id="password" name="password" required>
<label for="role">角色:</label>
<select id="role" name="role" required>
<option value="USER">用户</option>
<option value="ADMIN">管理员</option>
</select>
<button type="submit">注册</button>
</form>
<a href="/">返回首页</a>
</div>
</body>
</html>
测试类
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import java.util.Base64;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class SpringSecurityApplicationTests {
@LocalServerPort private int port;
@Autowired private TestRestTemplate restTemplate;
@Test void contextLoads() {}
@Test void testIndexPage() {
String response = restTemplate.getForObject("http://localhost:" + port + "/", String.class);
assertThat(response).contains("首页");
}
@Test void testUserPageWithoutAuthentication() {
ResponseEntity<Map> response = restTemplate.getForEntity("http://localhost:" + port + "/user", Map.class);
assertThat(response.getStatusCodeValue()).isEqualTo(302);
}
@Test void testUserPageWithUserAuthentication() {
String credentials = "user:user123";
String base64Credentials = Base64.getEncoder().encodeToString(credentials.getBytes());
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Credentials);
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange("http://localhost:" + port + "/user", HttpMethod.GET, entity, String.class);
assertThat(response.getStatusCodeValue()).isEqualTo(200);
assertThat(response.getBody()).contains("用户页面");
}
@Test void testAdminPageWithoutAuthentication() {
ResponseEntity<Map> response = restTemplate.getForEntity("http://localhost:" + port + "/admin", Map.class);
assertThat(response.getStatusCodeValue()).isEqualTo(302);
}
@Test void testAdminPageWithAdminAuthentication() {
String credentials = "admin:admin123";
String base64Credentials = Base64.getEncoder().encodeToString(credentials.getBytes());
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Credentials);
HttpEntity<String> entity = new HttpEntity<>(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 Security 提供的一种授权方式。
作用:
示例:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.passwordEncoder(NoOpPasswordEncoder.getInstance())
.withUser("admin").password("admin123").roles("ADMIN")
.and()
.withUser("user").password("user123").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasRole("USER")
.antMatchers("/").permitAll()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().permitAll();
}
}
小结:基于角色的授权是指 Spring Security 提供的一种授权方式,作用是实现用户授权、提供安全的编程模型。
定义:基于权限的授权是指 Spring Security 提供的一种授权方式。
作用:
示例:
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.passwordEncoder(NoOpPasswordEncoder.getInstance())
.withUser("admin").password("admin123").roles("ADMIN")
.and()
.withUser("user").password("user123").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasRole("USER")
.antMatchers("/").permitAll()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().permitAll();
}
}
小结:基于权限的授权是指 Spring Security 提供的一种授权方式,作用是实现用户授权、提供安全的编程模型。
在实际开发中,Spring Boot 与 Spring Security 的应用场景非常广泛,如:
示例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@SpringBootApplication
public class SecurityApplication {
public static void main(String[] args) {
SpringApplication.run(SecurityApplication.class, args);
}
}
@EnableWebSecurity
class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.passwordEncoder(NoOpPasswordEncoder.getInstance())
.withUser("admin").password("admin123").roles("ADMIN")
.and()
.withUser("user").password("user123").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/user/**").hasRole("USER")
.antMatchers("/").permitAll()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().permitAll();
}
}
@Controller
class SecurityController {
@GetMapping("/")
public String index() { return "index"; }
@GetMapping("/login")
public String login() { return "login"; }
@GetMapping("/user")
public String user() { return "user"; }
@GetMapping("/admin")
public String admin() { return "admin"; }
}
// 测试类
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class SecurityApplicationTests {
@LocalServerPort private int port;
@Autowired private TestRestTemplate restTemplate;
@Test void contextLoads() {}
@Test void testIndexPage() {
String response = restTemplate.getForObject("http://localhost:" + port + "/", String.class);
assertThat(response).contains("首页");
}
@Test void testUserPageWithoutAuthentication() {
ResponseEntity<Map> response = restTemplate.getForEntity("http://localhost:" + port + "/user", Map.class);
assertThat(response.getStatusCodeValue()).isEqualTo(302);
}
@Test void testUserPageWithUserAuthentication() {
String credentials = "user:user123";
String base64Credentials = Base64.getEncoder().encodeToString(credentials.getBytes());
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Credentials);
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange("http://localhost:" + port + "/user", HttpMethod.GET, entity, String.class);
assertThat(response.getStatusCodeValue()).isEqualTo(200);
assertThat(response.getBody()).contains("用户页面");
}
@Test void testAdminPageWithoutAuthentication() {
ResponseEntity<Map> response = restTemplate.getForEntity("http://localhost:" + port + "/admin", Map.class);
assertThat(response.getStatusCodeValue()).isEqualTo(302);
}
@Test void testAdminPageWithAdminAuthentication() {
String credentials = "admin:admin123";
String base64Credentials = Base64.getEncoder().encodeToString(credentials.getBytes());
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic " + base64Credentials);
HttpEntity<String> entity = new HttpEntity<>(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 Boot 与 Spring Security 的应用场景非常广泛,需要根据实际问题选择合适的安全框架。
本章我们学习了 Spring Boot 安全认证与授权,包括 Spring Security 的定义与特点、Spring Boot 与 Spring Security 的集成、配置、认证、授权及实际应用场景,学会了在实际开发中处理安全认证与授权问题。其中,Spring Security 的定义与特点、Spring Boot 与 Spring Security 的集成、配置、认证、授权及实际应用场景是本章的重点内容。从下一章开始,我们将学习 Spring Boot 的其他组件、微服务等内容。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online