知其然,知其所以然
Spring 全家桶 2026-10-20

FilterChainProxy:安全过滤器链的顺序,多条链怎么匹配

实测 Spring Security 7 的 FilterChainProxy:默认链有 16 个过滤器;两条链时每个请求只选第一条匹配的链(/api/** 链 11 个、兜底链 15 个);401 触发的 /error 派发会被兜底链拦下变成 302 到 /login;兜底链放在前面会在启动时失败;ignoring 的路径完全不经过过滤器,没有安全响应头,permitAll 的路径仍然经过 11 个过滤器。

Spring Security FilterChainProxy 过滤器链 securityMatcher 真实验证 动画演示
Spring 全家桶 2026-10-20

认证流程:AuthenticationManager、Provider 与 SecurityContext

实测 Spring Security 7 的认证流程:ProviderManager 里默认只有一个 DaoAuthenticationProvider;密码错与用户不存在都是 BadCredentialsException,耗时相近;禁用、锁定、凭据过期有各自的异常和事件;成功返回的是新对象,凭据被擦掉并多了 FACTOR_PASSWORD 权限;SecurityContext 默认只在请求线程里有,INHERITABLETHREADLOCAL 会让线程池里一直是第一次请求的用户。

Spring Security 认证 AuthenticationManager SecurityContext 真实验证 动画演示
Spring 全家桶 2026-10-20

PasswordEncoder:BCrypt 的 cost 与耗时,DelegatingPasswordEncoder

实测 Spring Security 7 的 PasswordEncoder:BCrypt strength 每加 2 耗时约 ×4(10 是 70.1 ms,12 是 274.6 ms,14 是 1105.2 ms);DelegatingPasswordEncoder 用 {id} 前缀选算法,没有前缀会抛异常,upgradeEncoding 可以识别旧哈希;encode 拒绝超过 72 字节的密码,但 matches 会忽略 72 字节之后的内容;Pbkdf2、SCrypt、Argon2 的默认参数耗时。

Spring Security PasswordEncoder BCrypt DelegatingPasswordEncoder 真实验证 动画演示
Spring 全家桶 2026-10-20

Session 与 SecurityContextRepository:登录态存在哪里

实测 Spring Security 7 的登录态:表单登录后 SecurityContext 存在服务端 HttpSession 的 SPRING_SECURITY_CONTEXT,cookie 只有 JSESSIONID(HttpOnly);登录前后 session id 默认会变,关掉后不变;STATELESS 模式不创建会话;自己写登录接口只 setContext 而不 saveContext,下一个请求就没登录;退出后旧 cookie 失效。

Spring Security Session SecurityContextRepository 登录态 真实验证 动画演示
Spring 全家桶 2026-10-20

CSRF:令牌怎么生成与校验

实测 Spring Security 7 的 CSRF:默认令牌每次取到的值不同(96 字符的掩码)但都能通过校验;POST、DELETE 不带令牌 403,GET、HEAD、OPTIONS 放行;登录后旧令牌作废;Cookie 方案下把 36 字符的 cookie 值原样放进请求头会被默认处理器拒绝,换成明文处理器才通过;ignoringRequestMatchers 只放行指定路径。

Spring Security CSRF 令牌 CookieCsrfTokenRepository 真实验证 动画演示
Spring 全家桶 2026-10-20

CORS 与 Security:预检为什么被 401 拦下

实测 Spring Security 7 加 Spring MVC 的 CORS:MVC 里配了 CORS 而 Security 没有 .cors() 时,预检(不带凭据的 OPTIONS)被认证拦成 401,没有任何 CORS 头;加上 http.cors(withDefaults) 后预检 200 并返回 allow-origin、allow-methods、allow-headers、max-age 1800,不允许的 Origin、方法、请求头都是 403;需要凭据时用 allowedOriginPatterns。

Spring Security CORS 预检 跨域 真实验证 动画演示
Spring 全家桶 2026-10-20

方法级安全:@PreAuthorize 与代理

实测 Spring Security 7 的方法级安全:@PreAuthorize 靠 CGLIB 代理实现,类内部自调用和 private 方法绕过检查,接口上的注解有效;@PostAuthorize 在方法执行之后才拒绝;@PreFilter 对不可变列表不报错也不过滤;@Secured 与 @RolesAllowed 在默认的 @EnableMethodSecurity 下完全不生效。

Spring Security 方法级安全 PreAuthorize AOP代理 真实验证 动画演示
Spring 全家桶 2026-10-20

授权决策:AuthorizationManager 与 ROLE_ 前缀

实测 Spring Security 7 的授权:hasRole("X") 等价于 hasAuthority("ROLE_X"),权限叫 ADMIN 的用户过不了 hasRole("ADMIN");hasRole("ROLE_ADMIN") 启动失败;规则按声明顺序第一个匹配的生效,写反会让 /a/admin/** 被 /a/** 的 USER 规则吞掉;anyRequest 之后不能再加 requestMatchers;RoleHierarchy 让 ADMIN 自动拥有 USER;自定义 AuthorizationManager 可以按请求信息决策。

Spring Security 授权 AuthorizationManager ROLE_前缀 RoleHierarchy 真实验证 动画演示
Spring 全家桶 2026-10-20

JWT 资源服务器:签名验证、时钟偏差与密钥轮换

实测 Spring Security 7 的 JWT 资源服务器:scope 映射成 SCOPE_ 权限、roles 声明默认被忽略;篡改、alg=none、HS256 混淆的令牌都被拒绝;默认的校验只看时间不看签发者,别的 iss 的令牌也会通过;时间偏差默认容忍 60 秒;JWKS 里 kid 不在缓存时会立即重新获取,切换到新密钥后旧密钥立即失效;JWKS 服务宕机时已缓存的密钥继续可用。

Spring Security JWT 资源服务器 JWKS 密钥轮换 真实验证 动画演示
Spring 全家桶 2026-10-20

OAuth2 授权码加 PKCE:用 Spring Authorization Server 跑通

用 Spring Authorization Server 跑通授权码加 PKCE:公开客户端不需要 client_secret,换令牌必须带 code_verifier;授权码只能用一次;缺 code_challenge 或用 plain 会被拒绝;redirect_uri 未注册时不重定向;公开客户端拿不到 refresh_token,机密客户端的 refresh_token 默认被复用;access_token 是 300 秒的 RS256 JWT。

Spring Security OAuth2 PKCE 授权码 Authorization Server 真实验证 动画演示
Spring 全家桶 2026-10-19

ApplicationContext.refresh():容器启动的那十几步各做了什么

实测 ApplicationContext.refresh() 的 12 个步骤:BeanDefinition 在 invokeBeanFactoryPostProcessors 里从 6 个涨到 15 个(最慢的一步,76456 µs);BeanFactoryPostProcessor、BeanPostProcessor 本身最先被创建;普通单例在 finishBeanFactoryInitialization 里创建,prototype 与 @Lazy 的 Bean 不创建;refresh 失败时已创建的单例会被销毁。

Spring IoC ApplicationContext refresh 容器启动 真实验证 动画演示
Spring 全家桶 2026-10-19

BeanDefinition:Bean 在被创建之前是什么

实测 BeanDefinition:手写、@Component 扫描、@Bean 方法三种来源的定义类型不同(@Bean 的定义类是 null、只有 factoryMethod);BeanFactoryPostProcessor 能在创建之前把 scope 改成 prototype;子定义会和 abstract 父定义合并成 RootBeanDefinition;同名定义在纯 Spring 里默认悄悄覆盖,SpringApplication 的上下文默认不允许。

Spring IoC BeanDefinition 容器 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号