Spring Security 示例——实现最简单的身份认证

首先,我们会编写一个只有最基本功能的 Spring Security 程序,只有最基本的最简单的身份验证,之后我们会随着学习不断完善这个项目

Spring Security 接入

引入依赖,我们引入 Spring Security 对应的starter

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

引入依赖后,如果你直接就开始写,在尝试去访问接下来写的接口就会自动跳转到一个 Spring Security 的默认登陆页面,默认用户名是 user, 密码会输出在控制台。

须登陆之后才能对接口进行访问。

创建Controller

控制器也没什么好说的,还是编写接口,只不过要注意,对于需要访问权限才能访问的接口,需要获取其登录的身份信息并且进行校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package hbnu.project.securitydemo.example.controller;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {

// 首页 - 公开访问
@GetMapping("/")
public String root() {
return "home";
}

// 另一个首页地址 - 公开访问
@GetMapping("/home")
public String home() {
return "home";
}

// 登录页 - 公开访问
@GetMapping("/login")
public String login() {
return "login";
}

// 用户页面 - 需要认证才能访问
@GetMapping("/user")
public String user(Model model) {
// 获取当前登录用户信息
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
model.addAttribute("username", authentication.getName());
model.addAttribute("roles", authentication.getAuthorities());
return "user";
}

// 管理员页面 - 需要认证且具有ADMIN角色才能访问
@GetMapping("/admin")
public String admin(Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
model.addAttribute("username", authentication.getName());
return "admin";
}
}

编写配置类

在这个其中,我们会配置一些安全过滤链和建立两个内存用户存储作为基础用户,要不然每次都要从控制台获取密码,蛮麻烦的,过滤器链如何配置我们后面会专门讲Spring Security 自定义配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package hbnu.project.securitydemo.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

// 配置安全过滤器链
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
// 配置URL访问权限
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/", "/home", "/css/**", "/js/**", "/images/**").permitAll() // 首页和静态资源允许匿名访问
.requestMatchers("/admin").hasRole("ADMIN") // 管理员页面需要ADMIN角色
.anyRequest().authenticated() // 其他所有请求都需要认证
)
// 配置表单登录
.formLogin(form -> form
.loginPage("/login") // 自定义登录页URL
.permitAll() // 允许所有人访问登录页
)
// 配置注销功能
.logout(logout -> logout
.permitAll() // 允许所有人访问注销功能
);

return http.build();
}

// 配置内存用户存储
@Bean
public UserDetailsService userDetailsService() {
// 创建两个用户:普通用户和管理员
UserDetails user = User.builder()
.username("user")
.password(passwordEncoder().encode("password"))
.roles("USER")
.build();

UserDetails admin = User.builder()
.username("admin")
.password(passwordEncoder().encode("admin"))
.roles("ADMIN")
.build();

return new InMemoryUserDetailsManager(user, admin);
}

// 配置密码编码器
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

启动测试

启动类没什么不一样的,忽略了,直接启动项目

对了我前端写的是thy页面引擎,使用动态链接可以会做自动的对应处理,会自动处理相对路径

image-20250920164610820

不知道为什么 css 没有给我加载进来,我开一下梯子试试

Spring Security 默认做了什么

我们几乎什么都没有做,为什么我们的应用就被保护起来了

Spring Security 在集成到 Spring Boot 应用后,会默认提供一系列 “开箱即用” 的安全功能,这些默认配置无需开发者手动编写代码,就能为应用提供基础安全防护。

Spring Security 的默认配置为应用提供了 “零配置启动” 的基础安全保障,包括用户认证、资源授权、常见攻击防护等核心功能。

默认的认证机制

  1. 生成默认用户

    • 自动创建一个用户名为 user 的默认用户,密码会在应用启动时随机生成并打印在控制台(格式:Using generated security password: xxxxxxxxxx)。
    • 该用户默认拥有 ROLE_USER 角色,可访问所有受保护资源。
  2. 表单登录

    • 提供默认的登录页面(路径为 /login),包含用户名、密码输入框和登录按钮。
    • 登录请求默认提交到 /login(POST 方法),登录失败会跳转至 /login?error,并显示错误信息。
    • 登录成功后,默认重定向到用户最初请求的受保护页面(若直接访问登录页,则重定向到 /)。
  3. 注销功能

    • 默认支持注销,请求路径为 /logout(GET 方法),注销后会销毁当前会话并跳转至 /login?logout

默认的授权规则

  1. 资源访问控制
    • 所有 HTTP 请求(除登录页 /login、注销页 /logout、静态资源等)均需要认证后才能访问。
    • 公开路径默认包含:/login(登录页)、/login?error(登录失败页)、/logout(注销页)、/webjars/**(WebJar 静态资源)、/css/**/js/** 等静态资源路径。
  2. 角色与权限
    • 默认用户仅拥有 ROLE_USER 角色,无其他特殊权限。
    • 授权判断默认区分角色前缀(ROLE_),例如 hasRole("USER") 实际匹配 ROLE_USER 权限。

默认安全防护

  1. 密码加密
    • 默认使用 BCryptPasswordEncoder 对密码进行加密存储(不允许明文密码),即使是默认生成的用户,其密码也是加密后的。
  2. CSRF 防护
    • 默认启用 CSRF(跨站请求伪造)防护,会为所有非 GET 请求生成 CSRF 令牌(存储在 Session 中),并要求请求携带该令牌(通常通过表单隐藏字段或请求头传递)。
    • 若请求未携带有效 CSRF 令牌,会被拒绝(返回 403 Forbidden)。
  3. 会话管理
    • 默认创建 HTTP 会话(SessionCreationPolicy.IF_REQUIRED),用于存储用户认证信息。
    • 登录时自动更换会话 ID(防止会话固定攻击)。
    • 会话过期时间默认由 Servlet 容器决定(通常为 30 分钟)。
  4. 安全响应头
    • 自动为响应添加安全相关的 HTTP 头,例如:
      • X-Content-Type-Options: nosniff(防止 MIME 类型嗅探)
      • X-Frame-Options: DENY(防止点击劫持)
      • X-XSS-Protection: 1; mode=block(启用浏览器 XSS 过滤)

默认集成与适配

  1. Spring Boot 自动配置
    • 无需手动注册过滤器链,Spring Boot 会自动创建 SecurityFilterChain 等核心组件。
    • 若引入 spring-boot-starter-web,默认适配 Servlet 环境;若引入 spring-boot-starter-webflux,则适配 Reactive 环境。
  2. 与其他组件集成
    • 若应用使用 Thymeleaf,默认支持 sec: 命名空间(如 <sec:authorize access="isAuthenticated()">),可在页面中直接判断用户权限。
    • 与 Spring Session 集成时,默认支持分布式会话(需额外依赖)。

简单说 Spring Security 的底层原理

回顾过滤器

Servlet 过滤器(Filter)和过滤器链(FilterChain) 的工作原理与 Spring Security 的工作息息相关,这是理解 Spring Security 核心机制的基础,因为 Spring Security 就是通过过滤器链来实现安全拦截的。

过滤器链(FilterChain)的结构如下

首先看示意图:

  • 客户端(Client)发送 HTTP 请求到服务器。
  • 服务器会创建一个 FilterChain(过滤器链),链中包含多个 Filter(过滤器)和最终的 Servlet(如 Spring MVC 中的 DispatcherServlet)。
  • 请求会按顺序经过 Filter₀Filter₁Filter₂ → … → Servlet,响应则按相反顺序返回(ServletFilter₂Filter₁Filter₀ → 客户端)。
image-20250920171340008

过滤器是请求处理的 “拦截器”,那么在正常情况下,在程序启动的时候就要被注册到对应的 Servlet 容器中才能工作,然后过滤器可以在请求到达 Servlet 之前(或响应返回客户端之前)做一些操作,采用的是 Spring Boot的形式,配置更是采用 Spring MVC 的形式,核心能力有两个:

  1. 拦截请求 / 响应:如果过滤器决定 “阻止” 请求,就可以直接向客户端返回响应,下游的过滤器和 Servlet 不会被调用。

    比如:Spring Security 的 “认证过滤器” 如果发现请求没有携带合法凭证,会直接返回 “401 未认证” 响应,不会让请求到达业务 Servlet

  2. 修改请求 / 响应:过滤器可以修改 HttpServletRequest(如添加请求头、修改参数)或 HttpServletResponse(如添加响应头、修改返回内容),再传递给下游组件。

过滤器的执行逻辑可以抽象成如下

1
2
3
4
5
6
7
8
9
10
11
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
// 1. 请求到达 Servlet 之前的逻辑(“前置处理”)
// 比如:记录请求日志、验证请求参数、添加自定义请求头...

// 2. 调用 chain.doFilter(request, response):
// 把请求传递给“下一个过滤器”或最终的 Servlet
chain.doFilter(request, response);

// 3. 响应从 Servlet 返回后的逻辑(“后置处理”)
// 比如:记录响应日志、统一包装返回结果、修改响应头...
}

chain.doFilter(...)这行代码决定了 “是否让请求继续向下游传递”。如果不调用它,下游的过滤器和 Servlet 就不会执行(相当于拦截了请求)。

因为每个过滤器只影响 “下游” 的组件,所以过滤器在链中的顺序非常关键。比如:“认证过滤器” 必须在 “授权过滤器” 之前执行 —— 先验证用户身份,再判断用户权限。

那么过滤器链和 Spring Security 的关系在上面说了,Spring Security 就是基于这个机制工作的,那么是如何体现的

  • 它会向 FilterChain 中添加一系列安全相关的过滤器(比如 UsernamePasswordAuthenticationFilter 处理表单登录、CsrfFilter 处理 CSRF 防护等)。
  • 这些过滤器按特定顺序执行,依次完成 “认证 → 授权 → 安全防护” 等操作,最终才会把合法请求交给业务 Servlet(如 Spring MVC 的 DispatcherServlet)。

过滤器链是 Servlet 规范的核心机制,Spring Security 借助它实现了 “无侵入式” 的安全拦截。我们之后会看 Spring Security 每个过滤器链以及其中的过滤器的

但如果 Filter 作为一个 spring 容器中 bean 对象管理呢?那么启用,禁用过滤器的操作就会更加灵活。那么,Spring Security 是如何处理这个问题的呢?

过滤链代理和委托过滤器代理

Spring Security 中 FilterChainProxyDelegatingFilterProxy 的角色相当重要,它们是 Spring Security 实现 “安全过滤器链管理” 的核心机制。

首先,FilterChainProxy就是Spring Security 的 “过滤器链代理”

  • 它是 Spring Security 提供的特殊 Filter,本身不直接做安全逻辑,而是代理到多个 SecurityFilterChain(安全过滤器链),实现调用了 Spring Security 自己的过滤器链,发挥安全框架的作用。
  • 每个 SecurityFilterChain 包含一系列 Spring Security 专属的过滤器(如认证过滤器、授权过滤器、CSRF 过滤器等),负责具体的安全操作。
  • 它通过代理模式,灵活管理多组安全过滤器链(比如不同的 URL 路径可以对应不同的 SecurityFilterChain)。

这样就算是实现了上面我们说的灵活管理 Filter 了

那么DelegatingFilterProxy是干什么的?

  • 它是“委托过滤器代理”,是 Servlet 规范的 Filter,但作用是桥接 Spring 容器和 Servlet 容器
  • 因为 FilterChainProxy 是 Spring 容器中的 Bean(由 Spring 管理生命周期),而 Servlet 容器(如 Tomcat)不直接认识 Spring Bean。而DelegatingFilterProxy 的作用就是会从 Spring 容器中找到 FilterChainProxy Bean,并将请求委托给它。

他们的关系可以看下图

image-20250920172205574

上述示意图的请求流向可以剖析成如下内容:

  1. 客户端发送请求 → 经过通用过滤器 Filter₀ → 到达 DelegatingFilterProxy
  2. DelegatingFilterProxy 从 Spring 容器中找到 FilterChainProxy Bean,把请求委托给它。
  3. FilterChainProxy 根据请求的 URL 等条件,选择对应的 SecurityFilterChain(一组 Spring Security 过滤器)。
  4. 请求经过 SecurityFilterChain 中的一系列安全过滤器(完成认证、授权、CSRF 防护等)→ 再回到 FilterChainProxy → 继续经过通用过滤器 Filter₂ → 最终到达业务 Servlet(如 Spring MVC 的 DispatcherServlet)。

那么为什么要这两层代理

DelegatingFilterProxy:解决 “Spring Bean 与 Servlet 容器的桥接”

  • Servlet 容器(如 Tomcat)启动时,会初始化自己的过滤器链,这些过滤器是独立于 Spring 容器的。
  • FilterChainProxy 是 Spring 容器中的 Bean(由 @Bean 或配置类定义),Servlet 容器无法直接调用 Spring Bean。
  • DelegatingFilterProxy 作为 “中间人”,让 Servlet 容器的过滤器能调用到 Spring 管理的 FilterChainProxy

FilterChainProxy:解决 “多组安全过滤器链的灵活管理”

  • 实际场景中,不同的请求可能需要不同的安全规则(比如 /api/** 路径需要 JWT 认证,/admin/** 路径需要会话认证 + 角色校验)。
  • FilterChainProxy 可以根据请求匹配规则(如 URL 模式),动态选择对应的 SecurityFilterChain,从而实现 “不同路径走不同的安全流程”。

之前的 “普通过滤器链” 是 Servlet 规范的原生链(Filter₀Filter₁Servlet),而 Spring Security 通过 DelegatingFilterProxyFilterChainProxy,在原生链中插入了 “Spring 管理的安全过滤器链”,从而实现 “非侵入式” 的安全增强。

这两层代理就是 Spring Security 的 架构设计亮点 了:

  • DelegatingFilterProxy 负责桥接 Spring 和 Servlet 容器,让 Spring 管理的 Bean 能参与 Servlet 过滤器链。
  • FilterChainProxy 负责管理多组安全过滤器链,让不同请求可以走不同的安全逻辑。

安全过滤链SecurityFilterChain

SecurityFilterChain 就是安全过滤器链,它是 Spring Security 专属的 “过滤器链单元”,它的核心使命是:

  • 封装一组特定的安全过滤器(如认证过滤器、授权过滤器、CSRF 过滤器等)。
  • FilterChainProxy 决定 “当前请求应该使用哪一组 SecurityFilterChain”,从而实现不同请求走不同安全逻辑

我们来看单 SecurityFilterChain 的流程

image-20250920173059259

看上图的流程:

  1. 客户端请求 → 经过通用过滤器 Filter₀ → 到达 DelegatingFilterProxy
  2. DelegatingFilterProxy 委托给 FilterChainProxy
  3. FilterChainProxy 选择对应的 SecurityFilterChain → 请求经过该链中的 Security Filter₀ → … → Security Filterₙ → 再回到 FilterChainProxy → 继续经过通用过滤器 Filter₂ → 最终到 Servlet

SecurityFilterChain 内部的 “安全过滤器” 是 Spring Security 实现具体安全功能的载体(比如 UsernamePasswordAuthenticationFilter 处理表单登录,CsrfFilter 处理 CSRF 防护)。

下图展示了 “多个 SecurityFilterChain 共存时,如何匹配请求” 的核心逻辑,这是 Spring Security 灵活性的体现:

image-20250920174112934

每个 SecurityFilterChain 都可以绑定特定的请求匹配规则(如 URL 模式、请求方法、请求头特征等)。

按照图中的示例来的话就是

  • SecurityFilterChain₀:匹配 URL 为 /api/** 的请求。
  • SecurityFilterChainₙ:匹配 URL 为 /** 的请求(所有请求,作为 “兜底” 规则)。

FilterChainProxy按配置顺序遍历所有 SecurityFilterChain,找到第一个匹配的链,然后只执行该链的过滤器(后续链不再执行)。只有第一个匹配的 SecurityFilterChain 被调用。

那么按照图上的示例,就可以这么理解

  • 请求 URL 为 /api/messages/
    • 先匹配 SecurityFilterChain₀/api/**)→ 执行该链的过滤器,不会再匹配后续的 SecurityFilterChainₙ(即使它也能匹配 /**)。
  • 请求 URL 为 /messages/
    • 不匹配 SecurityFilterChain₀/api/**)→ 继续匹配 SecurityFilterChainₙ/**)→ 执行该链的过滤器。

这样就实现了 Spring Security 过滤器链的自定义基础,因为SecurityFilterChain是可以自定义的:

  • 每个 SecurityFilterChain 内部的过滤器数量、类型都可以完全自定义(比如 SecurityFilterChain₀ 只需 3 个过滤器,SecurityFilterChainₙ 需 4 个)。
  • 甚至可以配置 “零过滤器” 的 SecurityFilterChain:用于让 Spring Security 完全忽略某些请求(比如静态资源路径,无需任何安全拦截)。

SecurityFilterChain 是 Spring Security 实现 “动态安全规则” 的核心载体:

  • 它封装了一组特定的安全过滤器,负责具体的安全逻辑。
  • 多个 SecurityFilterChain 可以通过优先级匹配,为不同请求提供定制化的安全防护。

理解这一点,就能明白 Spring Security 如何灵活应对复杂的业务场景(比如同时支持 “普通用户会话认证” 和 “第三方系统 JWT 认证”)。

从 DefaultSecurityFilterChain 再看默认配置

DefaultSecurityFilterChain 类是 Spring Security 中用于构建安全过滤器链的一个重要类,它实现了 SecurityFilterChainBeanNameAwareBeanFactoryAware 接口。

它的作用就是将 “请求匹配规则” 和 “一组安全过滤器” 绑定在一起,让特定的请求只能通过对应的安全过滤器处理。实现 “什么样的请求,用什么样的安全过滤器处理”

这个类是 SecurityFilterChain 中的其中一个过滤器链,也就是DefaultSecurityFilterChainSecurityFilterChain 的一个实现类。Spring Security 的整个安全机制,就是由一个或多个 DefaultSecurityFilterChain 组成的。

  • 默认配置中,Spring Security 会自动创建一个 “全局过滤器链”(RequestMatcher/**,匹配所有请求),包含 10+ 个核心过滤器(如认证、授权、CSRF 等)。实现了Spring Security 的默认行为。
  • 开发者可以自定义多个 DefaultSecurityFilterChain,实现 “不同路径不同安全规则”(比如 /api 用 JWT 过滤器,/admin 用会话过滤器)。

然后所有 DefaultSecurityFilterChain 会被 FilterChainProxy(安全过滤器链的 “调度中心”)管理。对应了上面说的当请求到达时,FilterChainProxy 会按顺序检查每个 DefaultSecurityFilterChainmatches() 方法,找到第一个匹配的链,然后执行该链中的所有过滤器。

image-20250920175840272

其中,filters的集合,存储了该安全过滤器链中包含的所有 Filter 实例,这些过滤器会按照顺序依次对请求进行处理。requestMatcher是一个 RequestMatcher 类型的对象,用于判断当前的 HttpServletRequest 是否匹配该过滤器链。也就是说,它决定了什么样的请求会进入到这个过滤器链中进行处理。

有两个构造函数,主要功能是初始化 requestMatcherfilters。第二个构造函数是实际执行初始化逻辑的,第一个构造函数只是做了一个参数转换,将可变参数 Filter... filters 转换为 List<Filter> 再调用第二个构造函数。

在第二个构造函数中,会先判断 filters 是否为空,如果为空,记录日志表示不会对匹配该 requestMatcher 的请求进行安全处理;如果不为空,记录日志说明会使用哪些过滤器对匹配的请求进行安全处理。

  • getRequestMatcher 方法
1
2
3
public RequestMatcher getRequestMatcher() {
return this.requestMatcher;
}

该方法用于获取 requestMatcherRequestMatcher决定 “管哪些请求”,外部可以通过这个方法得知当前过滤器链是根据什么规则来匹配请求的。

  • getFilters 方法
1
2
3
public List<Filter> getFilters() {
return this.filters;
}

用于获取当前过滤器链中包含的所有过滤器,方便对过滤器链的组成进行查看和分析。其中,List<Filter>:决定 “怎么处理请求”

  • matches 方法
1
2
3
public boolean matches(HttpServletRequest request) {
return this.requestMatcher.matches(request);
}

该方法用于判断传入的 HttpServletRequest 是否匹配当前过滤器链。实际上就是调用了 requestMatchermatches 方法,根据其内部定义的匹配规则(比如基于 URL 路径、请求方法等)来判断请求是否符合进入该过滤器链的条件。

  • toString 方法就不说了

其中有个 setBeanName 方法,就是设置该 bean 在 Spring 容器中的名称,把过滤器链当成 bean 管理

1
2
3
public void setBeanName(@NonNull String name) {
this.beanName = name;
}

最后举个例子理解这个类

当你引入 Spring Security 依赖后,默认会创建一个 DefaultSecurityFilterChain

  • RequestMatcheranyRequest()(匹配所有请求)。
  • filters:包含以下关键过滤器(简化版):
    • CsrfFilter:处理 CSRF 防护。
    • UsernamePasswordAuthenticationFilter:处理表单登录。
    • FilterSecurityInterceptor:最终的授权判断(检查用户是否有权限访问资源)。

当你访问 /admin 时:

  1. 请求被 DelegatingFilterProxy 拦截,交给 FilterChainProxy
  2. FilterChainProxy 发现默认的 DefaultSecurityFilterChain 匹配所有请求,于是执行它的过滤器链。
  3. 依次经过 CSRF 检查 → 登录状态检查(未登录则跳转登录页)→ 授权检查(判断是否有 ADMIN 角色)→ 最终允许 / 拒绝访问。

我们可以总结 Spring Security 为开发者提供了一整套基于过滤器链(Filter Chain)的安全防护机制。从用户发起 HTTP 请求,到经过多个安全过滤器的逐层检查,直至最终认证与授权完成。

我们来看一下 Spring Security 默认 DefaultSecurityFilterChain 启动的时候,默认加载的 16 个过滤器

image-20250920195856375

Spring Security 已经帮我们封装了大部分的过滤器,实际上我们主要关注以下两个方面即可:

  • 身份认证流程:如何通过表单登录(或其他方式)实现用户身份验证,及其内部如何利用 AuthenticationManager、ProviderManager 和多个 AuthenticationProvider 协同工作
  • 授权机制解析:如何通过安全拦截器(如 AbstractSecurityInterceptor)实现方法级别和 URL 级别的权限控制。

从 SecurityProperties 再看默认配置

其中,Spring Security 启动涉及到一个重要的类就是 SecurityProperties,是 Spring Boot 自动配置 Spring Security 时的核心配置属性类,它的作用是将外部配置(如 application.properties/yml)与 Spring Security 的默认行为关联起来,让开发者可以通过简单的配置项自定义 Security 的基础行为。

该类使用 @ConfigurationProperties("spring.security") 注解,说明它会读取配置文件中以 spring.security 为前缀的配置项,并映射到类的字段中。

例如,开发环境中只需一行配置 spring.security.user.password=123,就能用简单密码登录,无需复杂的用户配置;生产环境中再替换为自定义的 UserDetailsService,实现从数据库读取用户。

image-20250920181729604

这个配置类的核心结构包含两个内部静态类:

  • Filter:配置 Spring Security 过滤器的相关属性(如过滤器顺序、拦截 的请求类型)。
  • User:配置默认用户的相关属性(如用户名、密码、角色)。

先来看 User 内部类,它控制默认用户的生成

image-20250920181633655

Spring Security 默认会创建一个用户用于登录,而 User 内部类就是这个默认用户的 “配置源”,核心字段:

  • name:默认用户名为 user,可通过 spring.security.user.name 修改。
  • password:默认是随机 UUID(启动时打印在控制台),若通过 spring.security.user.password 手动设置,则使用自定义密码。
  • roles:默认是空集合,可通过 spring.security.user.roles 配置角色(如 ADMIN)。
  • passwordGenerated:标记密码是否是自动生成的(若手动设置密码,则为 false)。

Spring Boot 自动配置会读取 User 中的属性,创建一个内存用户(InMemoryUserDetailsManager),作为默认的认证用户。如果开发者没有自定义 UserDetailsService,这个默认用户就会生效。

再看 Filter 内部类,它控制 Security 过滤器的行为

image-20250920181740631

我们上面一直在说 Spring Security 的核心逻辑通过过滤器链实现,其中的Filter 内部类用于配置这个过滤器链的基础属性

  • order:过滤器的执行顺序,默认值为 -100

    Spring 中过滤器的 order 越小,执行越早。Security 过滤器需要在业务过滤器(如 DispatcherServlet)之前执行,因此默认值为负数。

    可通过 spring.security.filter.order 调整顺序

  • dispatcherTypes:指定过滤器拦截的请求类型,默认是 EnumSet.allOf(DispatcherType.class)(拦截所有类型的请求)。

    DispatcherType 包括 REQUEST(普通请求)、FORWARD(转发)、INCLUDE(包含)、ERROR(错误页)等。例如,若只想拦截普通请求,可配置为 [REQUEST]

Spring Boot 会根据 Filter 中的配置,初始化 DelegatingFilterProxy(前文提到的过滤器代理),并设置其执行顺序和拦截的请求类型,确保 Security 过滤器链能正确介入请求处理流程。

这样,这个类就实现了提供默认配置,实现 “零配置启动”的根本作用,当开发者引入 spring-boot-starter-security 但未做任何配置时,SecurityProperties 会提供一套默认值:

  • 默认用户 user + 随机密码,确保应用至少有一个可登录用户。
  • 过滤器按默认顺序执行,拦截所有请求,确保安全逻辑生效。

而且还允许开发者通过配置文件自定义基础行为,也算是 Spring Security 最基础的自动配置内容了

Spring Security 的核心架构

Spring Security中,整个安全流程围绕着一个核心组件展开:FilterChainProxy。它负责拦截所有 HTTP 请求,并将其传递给预先配置好的多个安全过滤器。这些过滤器中,最关键的包括:

  • UsernamePasswordAuthenticationFilter:处理基于表单提交的登录请求。
  • BasicAuthenticationFilter:处理 HTTP Basic 认证请求。
  • FilterSecurityInterceptor:负责权限授权,调用 AccessDecisionManager 来判定当前用户是否有权访问目标资源。
image-20250920200128472

具体的身份认证流程和授权在后面讲解