2026年4月9日 北京
本文登录AI助手后,系统梳理Spring Security认证授权体系的核心知识点,涵盖JWT原理、OAuth2协议以及两者的关系与区别,结合代码示例和面试要点,帮助开发者彻底吃透这个Java生态中最高频的安全技术模块。

一、痛点切入:传统认证方式为什么不够用了?
在Web开发初期,最主流的认证方案是Session认证。当用户输入账号密码登录成功后,服务器会在内存中创建一个Session对象,并将Session ID通过Cookie返回给浏览器。浏览器后续的每次请求都会自动携带这个Cookie,服务器根据Session ID找到对应的会话信息,确认用户身份。

这个流程看起来简单直观,但在实际开发中暴露出一系列问题:
服务器内存压力:每个登录用户都会在服务器内存中保留一份Session数据。当用户量达到百万级别时,仅Session存储就可能消耗数十GB内存。
分布式环境扩展困难:用户的第一次请求落到服务器A,Session存储在A上;第二次请求如果落到服务器B,B找不到对应的Session,用户就被“踢”下线了。解决这个问题需要引入Redis做Session共享,增加了架构复杂度和网络开销。
跨域场景不友好:Cookie遵循同源策略,在前后端分离的架构下,前端部署在
localhost:3000,后端部署在localhost:8080,Cookie无法跨域自动携带,需要复杂的CORS配置才能勉强工作。CSRF攻击风险:Cookie会自动附加到请求中,攻击者可以利用这一点构造恶意请求,诱导用户在已登录状态下执行非本意的操作。
这些问题在单体应用时代尚可接受,但在微服务、前后端分离、跨端(Web/APP/小程序)并存的今天,Session认证的局限性越来越明显-30。正是基于这些痛点,无状态的Token认证方案逐渐成为主流。
二、核心概念:JWT是什么?
JWT(JSON Web Token,JSON网络令牌) 是一种基于RFC 7519开放标准定义的紧凑、URL安全的令牌格式,用于在网络双方之间以JSON对象的形式安全传递信息-48。
拆解JWT的核心特点:
| 特点 | 含义 | 价值 |
|---|---|---|
| 紧凑 | 字符串形式,体积小 | 适合在HTTP Header中传输,网络开销小 |
| 自包含 | 令牌本身携带用户信息 | 服务端不需要额外存储,拿到Token即可知道用户是谁 |
| 无状态 | 服务端不保存任何会话信息 | 天然支持水平扩展,任意节点都能验证Token |
一句话理解JWT:JWT就是一个加密的、自带用户信息的“身份令牌”。服务端不用存Session,直接验签即可完成认证-48。
JWT的结构:JWT由三段Base64编码的字符串组成,用英文句点.分隔,格式为xxxxx.yyyyy.zzzzz-11。
以以下JWT为例:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5cHeader(头部) —— 声明令牌的类型和签名算法。例如:
{"alg":"HS256","typ":"JWT"},表示使用HMAC-SHA256算法进行签名-48。Payload(负载) —— 存放实际的用户数据,如用户ID、用户名、角色、过期时间等。⚠️ 注意:Payload只是Base64编码,不是加密!任何人都可以解码查看其中的内容,因此绝对不要存放密码、银行卡号等敏感信息-48。
Signature(签名) —— 最重要的一段。签名 = 对
Base64(Header)+"."+Base64(Payload)使用密钥进行HMAC-SHA256加密的结果-48。只有服务端持有密钥,任何对Header或Payload的篡改都会导致签名验证失败,从而实现防篡改保护。
三、关联概念:OAuth 2.0是什么?
如果说JWT解决的是“令牌长什么样”的问题,那么OAuth 2.0解决的就是“令牌怎么颁发、怎么授权”的问题。
OAuth 2.0是一个关于授权的开放标准框架,核心思路是通过各类认证手段认证用户身份后,向第三方应用颁发Token(令牌),使得第三方应用可以在限定时间、限定范围内访问指定资源-31。
OAuth 2.0引入了几个关键角色:
资源所有者:拥有被访问资源的用户
客户端:需要获取资源的第三方应用
授权服务器:负责认证用户并颁发Token
资源服务器:持有用户资源,通过Token验证来授权访问-31
OAuth 2.0定义了四种授权模式:
| 模式 | 适用场景 | 安全性 |
|---|---|---|
| 授权码模式 | 有后端服务的Web应用(如微信/QQ登录) | 最安全,有code和token两层防护 |
| 隐式模式 | 纯前端单页应用 | 安全性较低,已逐渐被淘汰 |
| 密码模式 | 高度信任的内部应用 | 不推荐,Client会接触到用户密码 |
| 客户端模式 | 服务器之间的机器通信 | 无用户参与,适合API调用-31 |
四、概念关系:OAuth 2.0和JWT到底什么关系?
这是面试中最高频的混淆点。很多开发者把JWT和OAuth混为一谈,甚至认为它们是互斥的二选一。实际上:
OAuth 2.0是一个授权协议(定义流程),JWT是一个令牌格式(定义数据结构)-29。
| 对比维度 | OAuth 2.0 | JWT |
|---|---|---|
| 本质 | 授权框架 / 协议 | 令牌格式 / 数据结构 |
| 核心职责 | 定义如何获取和管理访问权限 | 定义如何打包和传递信息 |
| 状态 | 有状态(需要授权服务器管理令牌) | 无状态(本地即可验证) |
| 令牌作废 | 支持,授权服务器可直接撤销 | 无法提前作废,需额外机制 |
| 能独立使用吗 | 可以,但需要一个令牌格式来承载 | 可以,用于简单场景的签名断言 |
在实际的生产系统中,OAuth 2.0和JWT往往配合使用:OAuth 2.0定义授权流程,JWT作为Access Token的格式被OAuth 2.0签发和使用-29。这就好比OAuth是“交通规则”,JWT是“行驶证”——规则规定了你该怎么拿到证,而证本身长什么样、包含哪些信息,由格式决定。
五、代码示例:Spring Security + JWT实现无状态认证
下面是一个精简但完整的实现示例,演示如何在Spring Boot中使用JWT进行无状态认证。
步骤1:添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.12.3</version> </dependency>
步骤2:JWT工具类(生成与验证Token)
@Component public class JwtUtil { @Value("${jwt.secret}") private String secret; // 从配置文件中读取密钥 // 生成Token:包含用户名和角色信息 public String generateToken(String username, String roles) { return Jwts.builder() .setSubject(username) .claim("roles", roles) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + 3600000)) // 1小时过期 .signWith(SignatureAlgorithm.HS256, secret) .compact(); } // 验证Token:校验签名和过期时间 public Boolean validateToken(String token) { try { Jwts.parser().setSigningKey(secret).parseClaimsJws(token); return true; } catch (Exception e) { return false; // 签名错误/过期/格式错误均返回false } } }
步骤3:JWT认证过滤器
@Component public class JwtAuthenticationFilter extends OncePerRequestFilter { @Autowired private JwtUtil jwtUtil; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { // 1. 从请求头中提取Token String token = request.getHeader("Authorization"); if (token != null && token.startsWith("Bearer ")) { token = token.substring(7); // 2. 验证Token if (jwtUtil.validateToken(token)) { // 3. 解析Token获取用户信息,存入SecurityContext String username = Jwts.parser().setSigningKey(secret) .parseClaimsJws(token).getBody().getSubject(); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>()); SecurityContextHolder.getContext().setAuthentication(authentication); } } // 4. 继续执行后续过滤器链 chain.doFilter(request, response); } }
关键流程解析:
用户登录 → 服务端验证账号密码 → 调用
jwtUtil.generateToken()生成JWT并返回客户端客户端将JWT存储在
localStorage中,每次请求在Authorization请求头中携带服务端的
JwtAuthenticationFilter拦截每个请求,提取并验证Token,验证通过后将用户信息注入Spring Security上下文后续业务逻辑可直接从
SecurityContextHolder中获取当前用户信息-3-31
六、底层原理:Spring Security如何支撑这些功能?
Spring Security能够灵活支持JWT、OAuth 2.0等多种认证方式,底层依赖以下核心技术:
过滤器链(Filter Chain) :Spring Security的核心架构是一组Servlet过滤器。每个请求依次经过这些过滤器,分别处理认证、会话管理、异常转换和访问控制-40。
SecurityContextHolder:这是一个线程绑定的上下文容器,默认使用
ThreadLocal存储当前请求的用户认证信息。认证成功后,用户信息被存入SecurityContextHolder,同一请求链路上的后续组件可以直接读取-。AuthenticationManager & ProviderManager:认证管理器负责协调多种认证方式。
DaoAuthenticationProvider是其中最常用的实现,它通过调用UserDetailsService从数据库加载用户信息,并用PasswordEncoder比对密码-。注解驱动的方法级权限控制:
@PreAuthorize和@Secured注解允许在Service层方法上直接声明访问权限,通过SpEL表达式实现细粒度的权限校验-40。底层依赖:JWT的实现依赖于加密算法(HMAC-SHA256、RSA等)和Base64编码;OAuth 2.0的完整实现则依赖HTTP重定向机制、Token端点和发现协议(OIDC Discovery)。
了解这些底层原理后,你会发现Spring Security的架构高度解耦——你只需要实现相应的接口(如UserDetailsService),框架会自动完成剩余的流程编排。
七、高频面试题与参考答案
Q1:Spring Security是什么?它的核心功能有哪些?
参考答案:Spring Security是Spring生态中用于安全管理的主流框架,为Java应用提供完整的认证(Authentication)和授权(Authorization)解决方案-39。其核心功能包括:①支持多种认证方式(表单登录、JWT、OAuth2、LDAP等);②细粒度的权限控制(URL级别和方法级别);③内置常见攻击防护(CSRF、Session Fixation、点击劫持);④与Spring Boot、Spring MVC无缝集成-40。
Q2:JWT由哪几部分组成?为什么说它是“自包含”的?
参考答案:JWT由三部分组成:Header(头部)、Payload(负载)和Signature(签名),用.分隔-48。之所以说它“自包含”,是因为JWT的Payload中直接存储了用户信息(如用户ID、角色、过期时间),服务端收到JWT后只需验证签名即可获取所有必要信息,无需查询数据库,从而实现无状态认证-48。
Q3:OAuth 2.0和JWT的区别是什么?
参考答案:OAuth 2.0是一个授权框架/协议,定义了第三方应用如何获取访问令牌(Token)以及令牌的生命周期管理;JWT是一种令牌格式,定义了令牌的数据结构和编码方式-29。两者的关系是:OAuth 2.0定义“怎么拿到Token”,JWT定义“Token长什么样”。在实际系统中,OAuth 2.0通常使用JWT作为其Access Token的格式-29。
Q4:JWT有什么缺点?如何应对?
参考答案:JWT的主要缺点包括:①Token无法提前作废,一旦签发必须等到过期时间才能失效,如需作废需额外维护黑名单-;②Payload可被解码,不能存放敏感信息;③Token体积较大,每次请求都携带,增加网络开销-30。应对策略:设置较短的过期时间配合Refresh Token机制实现静默续期;敏感信息不应存入Payload;在极端安全性要求下,可考虑使用服务端存储Session并配合JWT的方式-。
Q5:Session认证和JWT认证的本质区别是什么?
参考答案:Session认证是有状态的——用户信息存储在服务端内存/Redis中,服务端必须维护每个用户的会话状态。JWT认证是无状态的——用户信息编码在Token本身中,服务端只需验证签名即可,不存储任何会话数据-30。JWT天然适合分布式、微服务架构,而Session认证在集群环境下需要额外做共享存储-30。
八、总结
本文围绕Spring Security认证授权体系,系统梳理了以下核心知识点:
Session认证的痛点:服务器内存压力、分布式扩展困难、跨域不友好 → 催生了无状态的Token认证方案
JWT的定义与结构:紧凑、自包含、无状态的令牌格式,由Header.Payload.Signature三部分组成
OAuth 2.0的定义:授权框架,定义如何颁发和管理访问令牌
两者的关系:OAuth是协议(定义流程),JWT是格式(定义数据结构),生产中常配合使用
代码实现:JWT工具类 + 认证过滤器,实现无状态认证
底层原理:过滤器链、SecurityContextHolder、AuthenticationManager
重点提示:面试中90%被问到的JWT相关题目,答案都可以归结到“无状态”和“自包含”这两个关键词上。记住:Session存储位置在服务端,JWT存储在客户端——这个区别能帮你解答绝大多数对比类题目。
本系列后续文章将继续深入:Spring Security过滤器链源码剖析、OAuth 2.0授权码模式完整实战、微服务网关层鉴权设计与实现,敬请期待!
扫一扫微信交流