注:后续项目架构完善后会上传至Git,下一章节将实际介绍项目中的配置使用
学习可参考该网址:https://www.cnblogs.com/lvlaotou/p/18114025
1.概述
Spring Security 是一个强大的框架,用于保护基于 Spring 的应用程序。它提供了全面的认证和授权功能,使得安全机制与应用逻辑相分离。以下是 Spring Security 的基本使用指南,包括如何集成 Spring Security、定义用户角色和权限、以及自定义安全配置。
在 Java 生态中,目前有 Spring Security 和 Apache Shiro 两个安全框架,可以完成认证和授权的功能。
1.1【认证】与【授权】
(1)认证(Authentication)
-
定义: 验证用户身份的过程,用于确定用户或系统是否是它声称的身份。
-
目的: 确认一个实体(用户、设备或系统)确实是其声称的身份。通过这个过程,系统可以确保进入的请求者的身份是真实的,并且其具备的身份信息是有效的。
-
举例: 当你登录电子邮件账户时,输入你的用户名和密码,系统验证这些信息以确认你是该账户的合法用户。这是认证的过程。
(2)授权(Authorization)
-
定义: 指在认证之后,确定一个经过认证的用户或系统在资源上的访问权限的过程。
-
目的: 根据用户的权限设置,决定用户是否有权访问特定资源或执行某些操作。它决定了“谁能做什么”。
-
举例: 登录电子邮件账户后,你可以读取、撰写和删除邮件。这是基于你的授权——因为你是账户的拥有者。而你不能访问其他用户的电子邮件,因为你没有授权。
-
如何实现:
- 基于角色的访问控制(RBAC): 根据用户的角色来分配访问权限,例如管理员、编辑者、查看者等。
- 基于属性的访问控制(ABAC): 使用更细粒度的控制,基于用户属性、环境条件和资源属性来决定访问权限。
- 访问控制列表(ACL):指定哪些用户或组可以访问特定的资源以及他们的权限(例如,读取、写入、执行)。
(3)【认证】与【授权】的区别
方面 | 认证 (Authentication) | 授权 (Authorization) |
---|---|---|
定义 | 验证用户身份的过程 | 确定用户访问权限的过程 |
问题 | “你是谁?” | “你能做什么?” |
目的 | 确保用户是其声称的身份 | 决定用户是否有权访问某些资源或执行特定操作 |
执行时机 | 认证通常在授权之前执行 | 授权在认证之后执行 |
示例 | 用户使用用户名和密码登录系统 | 根据用户角色允许访问特定的文件或功能 |
2.快速入门
2.1 添加依赖
首先,在 pom.xml
中添加 Spring Security
的依赖项:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2.2 配置文件
在 application.yml
中,添加 Spring Security
配置,如下:
server:
port: 48081
# Spring Security 配置项,对应 SecurityProperties 配置类
# `UserDetailsServiceAutoConfiguration` 会基于配置的信息创建一个用户 `User `在内存中。
spring:
security:
# 配置默认的 InMemoryUserDetailsManager 的用户账号与密码。
user:
name: user # 账号
password: 123 # 密码
roles: ADMIN # 拥有角色
- 默认情况下,
Spring Boot
UserDetailsServiceAutoConfiguration
自动化配置类,会创建一个内存级别的InMemoryUserDetailsManager
Bean
对象,提供认证的用户信息。
这里 spring.security.user 配置项,
UserDetailsServiceAutoConfiguration
会基于配置的信息创建一个用户User
在内存中。如果,未添加 spring.security.user 配置项,
UserDetailsServiceAutoConfiguration
会自动创建一个用户名为user
,密码为UUID
随机的用户User
在内存中。
2.3 简单测试
(1)编写测试Controller
import com.server.pojo.MobileDo;
import jakarta.validation.Valid;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/admin")
@Validated
public class TestController {
@GetMapping("/demo")
public String testDemo() {
return "测试成功!!";
}
}
(2)项目启动
项目启动浏览器访问 http://127.0.0.1:48081/admin/demo
接口。因为未登录,所以被 Spring Security
拦截到登录界面(因为我们没有自定义登录界面,所以默认会使用 DefaultLoginPageGeneratingFilter
类,生成以下登录界面)。如下图所示:
输入我们在「2.2 配置文件」中配置的「user/user」账号,进行登录。登录完成后,因为 Spring Security
会记录被拦截的访问地址,所以浏览器自动动跳转 http://127.0.0.1:48081/admin/demo
接口。访问结果如下图所示:
3. 进阶使用(Spring Security 3.0及以上)-权限配置
在Spring Security 3.0
中要配置 Spring Security
跟以往是有些不同的,比如不在继承WebSecurityConfigurerAdapter
。
3.1 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version>
</dependency>
3.2 配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import static org.springframework.security.config.Customizer.withDefaults;
@Configuration
@EnableMethodSecurity(securedEnabled = true)
public class SecurityConfig {
@Bean
// 配置用户信息
public UserDetailsService userDetailsService() {
// 配置两个用户,一个具有 USER 角色,一个具有 ADMIN 角色
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withUsername("user").password(passwordEncoder().encode("1234")).roles("USER").build());
manager.createUser(User.withUsername("admin").password(passwordEncoder().encode("123")).roles("ADMIN").build());
return manager;
}
@Bean
// 配置密码编码器
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
// 配置安全过滤器链
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeHttpRequests(authz -> authz
.requestMatchers("/admin/demo").hasRole("ADMIN") // 只有具有 ADMIN 角色的用户可以访问 /admin 下的资源
.requestMatchers("/admin/user").hasRole("USER") // 只有具有 USER 角色的用户可以访问 /user 下的资源
.anyRequest().authenticated()// 其他任何请求都需要认证
)
.formLogin(withDefaults()) // 启用默认的表单登录
.logout(withDefaults()); // 启用默认的注销
// 认证用户时用户信息加载配置,注入springAuthUserService
httpSecurity.httpBasic(withDefaults());
return httpSecurity.build();
}
}
3.3 简单测试
(1)编写测试Controller
import com.server.pojo.MobileDo;
import jakarta.validation.Valid;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/admin")
@Validated
public class TestController {
@PostMapping("/test")
public String checkService(@Valid @RequestBody MobileDo mobileDo) {
return "测试成功!!";
}
@GetMapping("/demo")
public String testDemoAdminRole() {
return "ADMIN测试成功!!";
}
@GetMapping("/user")
public String testDemoUserRole() {
return "USER测试成功!!";
}
@GetMapping("/other")
public String testDemoOtherRole() {
return "other测试成功!!";
}
}
(2)项目启动
项目启动浏览器访问 http://127.0.0.1:48081/admin/demo
接口。因为未登录,所以被 Spring Security
拦截到登录界面,使用USER
角色的用户登录。如下图所示:
输入我们在「3.2 配置类」中配置的「user/1234」账号,进行登录。登录完成后,因为 Spring Security
会记录被拦截的访问地址,以及会判断该角色是否拥有该权限,因为user用户没有该缺陷,所以访问结果如下图所示: