欢迎光临
我们一直在努力

Spring Security 从入门到精通

一句话先定调:Spring Security 到底在干嘛?

作为一个小白,我们只需要知道: Spring Security 就是一个“站在门口的保安系统”。

每一个 HTTP 请求进来,它都会问三件事:

1. 你是谁? → Authentication(身份认证)
2. 你能干什么? → Authorization(权限校验)
3. 我现在记住你了吗? → SecurityContext(身份状态)

一、整体架构鸟瞰(先有全局地图)

所有 Spring Security 的工作,都发生在 Controller 之前

流程长这样:

浏览器发请求

Spring Security 过滤器链(大门口)

身份认证(你是谁)

权限校验(你能干啥)

Controller / Service(业务代码)

二、Spring Security 本质是什么?

很多同学学习 Spring Security 的时候,都会误会:

Spring Security = 注解+配置类

其真正的本体是一整条安全过滤器链,每个过滤器只干一条小事,但连起来就是完整安全系统

三、请求是怎么进 Spring Security 的?

1. Tomcat 和 Spring 本来是两个世界

Tomcat 只认识:

  • Servlet
  • Filter
  • Listener

它根本不知道什么是 Spring Bean。

而 Spring Security 的过滤器,全部是 Spring 管理的 Bean。

那问题来了:

Tomcat 怎么调用 Spring 的过滤器?

2. DelegatingFilterProxy(桥梁)

DelegatingFilterProxy 的结构是这样的:

Tomcat
└── DelegatingFilterProxy
└── Spring 管理的 FilterChainProxy
└── 一堆 Security Filter

你可以把它理解成:

Tomcat 把请求交给一个“中介” 这个中介再把请求转交给 Spring Security

四、真正干活是的:FilterChainProxy

Spring Security 内部大概有 20 多个过滤器,按顺序执行。

你不用全部记住,只要知道几个关键的:

顺序过滤器干什么
1 SecurityContextHolderFilter 创建“身份存储盒”
2 UsernamePasswordAuthenticationFilter 表单登录
3 BearerTokenAuthenticationFilter JWT 登录
4 AnonymousAuthenticationFilter 匿名用户
5 ExceptionTranslationFilter 捕获安全异常
6 AuthorizationFilter 权限校验

你可以理解成:

请求就像坐传送带 每个过滤器检查一次 最后决定:放行 or 拦截

五、SecurityContext 是什么?(核心中的核心)

通俗点来讲:

SecurityContext 就是“当前请求的身份盒子”

它的目标只有一个:

在任何地方,不传参数,也能知道:

  • 当前用户是谁
  • 有什么权限
  • 是否已登录

它的结构其实非常简单

接口:

public interface SecurityContext {
Authentication getAuthentication();
void setAuthentication(Authentication authentication);
}

实现类:

public class SecurityContextImpl implements SecurityContext {
private Authentication authentication;
}

SecurityContext 只是一个盒子 真正的“用户信息”在 Authentication 里

六、Authentication 是真正的“身份对象”

它包含四样核心东西:

public interface Authentication {
Object getPrincipal(); // 你是谁
Object getCredentials(); // 你的凭证(密码 / token)
Collection<?> getAuthorities(); // 你的权限
boolean isAuthenticated(); // 是否登录成功
}

可以理解为:

字段含义
principal 当前用户
credentials 登录凭证
authorities 权限列表
authenticated 是否认证通过

七、principal 到底是什么?(小白最容易卡死的点)

情况一:登录前

Authentication auth = new UsernamePasswordAuthenticationToken("zhangsan", "123456");

这时候:

principal = 用户名
credentials = 密码
authenticated = false


情况二:登录成功

principal = UserDetails对象
credentials = null
authenticated = true

为什么密码是 null?

因为密码已经用完了 再存着是安全隐患


情况三:JWT

你自己定义一个用户对象(LoginUser):

principal = LoginUser
authenticated = true

八、用户信息到底存哪了?

答案是这句:

SecurityContextHolder.getContext().setAuthentication(authentication);

用户信息不在 Controller,不在 Service, 也不在 SecurityContextHolder 这个类里, 而是存在“当前请求线程”中。

很多人看到名字会误会:

SecurityContextHolder = 保存 SecurityContext 的地方

其实不是。

来看它最核心的一行代码:

private static final ThreadLocal<SecurityContext> contextHolder
= new ThreadLocal<>();

这一行才是真相。

关于ThreadLocal,你可以这样理解:

ThreadLocal 就是“给每个线程准备的一个小抽屉”

  • 同一个 ThreadLocal
  • 不同的线程
  • 看到的是完全不同的数据

也就是说:

线程A → 自己的 SecurityContext
线程B → 自己的 SecurityContext

互不干扰。

九、为什么这样设计?

因为:

一个 HTTP 请求 = 一个线程

所以:

  • Filter
  • Controller
  • Service
  • Repository

全部跑在同一个线程里

这就意味着:

只要线程记住了用户 整个请求链路都能拿到用户

十、一次 JWT 请求完整流程(小白必看)

1. 请求进来

线程是空的:

ThreadLocal 里什么都没有


2. JWT Filter 解析 Token

LoginUser user = jwtService.parse(token);


3. 创建 Authentication

Authentication auth =
new UsernamePasswordAuthenticationToken(
user,
null,
authorities
);


4. 放进线程

SecurityContextHolder.getContext()
.setAuthentication(auth);

此时状态是:

当前线程
└── SecurityContext
└── Authentication
└── LoginUser


5. Controller 里直接拿

Authentication auth =
SecurityContextHolder.getContext().getAuthentication();

不需要传参数,不需要查 session。


十一、请求结束后发生什么?

Spring Security 最外层会执行:

SecurityContextHolder.clearContext();

也就是:

把线程里的用户信息清掉

为什么?

因为:

线程是复用的 不清就会“用户串号” 这是严重安全事故

十二、终极总结

Spring Security 没有“全局保存用户” 它只是让“当前请求的线程记住用户”

请求结束,线程清空 下一个请求,重新来过

以上就是笔者对于 Spring Security 知识的讲解,如有错误,欢迎广大同学指正!

赞(0)
未经允许不得转载:171主机测评 » Spring Security 从入门到精通
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址