一文吃透 OAuth2.0:核心原理 + SpringBoot + JWT 实战整合
一、OAuth2.0 到底是什么?
1.1 官方定义
OAuth2.0 是开放授权协议,是一个行业标准的授权方案,核心目的是“安全授权、不暴露密码”。
作用:让第三方应用在不获取用户密码的情况下,安全地授权访问用户资源。
1.2 大白话理解(一看就懂)
你用 微信登录抖音 时,有没有发现:抖音从来不会让你输入微信密码?
流程很简单:点击微信登录 → 跳转到微信授权页 → 你点击“同意” → 直接登录抖音。
这就是 OAuth2.0 的核心逻辑!它相当于一个“安全中介”,让抖音和微信之间建立授权关系,却不泄露你的微信密码。
✅ 核心优势:
-
不暴露密码,安全性更高
-
权限可控,可随时取消授权(比如在微信里取消抖音的授权)
-
无状态,适合分布式、微服务架构
-
行业标准,所有大厂都在用(微信、支付宝、GitHub 等)
二、OAuth2.0 四大核心角色
OAuth2.0 有四个固定角色,缺一不可,记住这四个角色,就能轻松理解所有授权流程:
1. Resource Owner(资源所有者)
就是 用户本人(比如你用微信登录抖音,你就是资源所有者),拥有可被访问的资源(头像、昵称、手机号等)。
2. Client(客户端)
就是 第三方应用(比如抖音、小红书、各种网站),需要获取用户的资源来完成功能(比如抖音获取你的微信头像用于登录)。
3. Authorization Server(授权服务器)
负责 登录、校验、颁发 Token 的认证中心(比如微信的认证服务器),核心作用是验证用户身份,给客户端颁发访问凭证(Token)。
4. Resource Server(资源服务器)
存放用户数据、提供业务接口的服务(比如微信的用户信息服务器、你自己项目的接口服务),只有拿到合法 Token,才能访问它的资源。
三、OAuth2.0 四种授权模式(重点掌握2种)
OAuth2.0 定义了 4 种获取 Token 的方式(授权模式),不同场景用不同模式,企业开发中只需要重点掌握2种,其余2种几乎不用。
3.1 授权码模式(最安全、最标准,首选!)
这是最常用、最安全的模式,也是第三方登录(微信、QQ、GitHub)的核心模式,流程稍微复杂,但安全性最高。
完整流程:
-
客户端(抖音)跳转至授权服务器(微信)的授权页面;
-
用户(你)在授权页面点击“同意”,授权客户端访问自己的资源;
-
授权服务器返回一个 code(授权码) 给客户端;
-
客户端拿着 code,向授权服务器换取 access_token(访问令牌);
-
客户端拿着 access_token,向资源服务器请求用户资源(比如微信头像)。
适用场景:第三方登录、开放平台(比如支付宝开放接口)、面向外部用户的系统。
3.2 密码模式(内部系统专用)
流程最简单,直接用用户的账号密码换取 Token,不需要跳转授权页面。
完整流程:
-
用户在客户端(公司内部系统)输入账号密码;
-
客户端拿着账号密码,向授权服务器请求 Token;
-
授权服务器验证账号密码,验证通过后,直接返回 access_token。
适用场景:公司内部系统(比如OA、CRM)、统一登录平台,只有内部人员使用,安全性可控。
3.3 简化模式(不推荐)
跳过授权码环节,直接返回 access_token,安全性低,适合纯前端应用(无后端),现在几乎不用。
3.4 客户端模式(服务间调用)
不需要用户参与,客户端(服务)直接向授权服务器请求 Token,用于服务之间的调用(比如微服务之间的接口调用)。
四、OAuth2.0 核心令牌(3个关键)
不管哪种授权模式,最终都是为了获取 Token,OAuth2.0 有3个核心令牌,必须分清:
1. access_token(访问令牌)
核心凭证,用于访问资源服务器的接口,短时效(一般1~2小时),过期后需要重新获取。
作用:证明客户端已经获得用户授权,可以访问用户资源。
2. refresh_token(刷新令牌)
用于刷新 access_token 的凭证,长时效(一般7~30天),access_token 过期后,不需要重新登录,用 refresh_token 就能换取新的 access_token。
作用:提升用户体验,避免频繁登录。
3. scope(授权范围)
规定客户端能访问的资源范围,比如“只允许访问用户头像和昵称”“允许访问用户手机号”,避免客户端过度获取用户资源。
五、OAuth2.0 与 JWT 关系
很多人混淆这两个概念,甚至认为它们是“二选一”,其实它们是互补关系,不是替代关系!
用一句话区分:
-
OAuth2.0:是 授权协议/规范,规定了“怎么认证、怎么授权、怎么获取 Token”的流程;
-
JWT:是 令牌格式,规定了 Token 应该怎么存储数据、怎么加密、怎么解析;
-
Spring Security:是 安全框架,负责实现 OAuth2.0 协议、生成 JWT Token、控制接口权限。
举个例子:OAuth2.0 相当于“快递流程规范”,JWT 相当于“快递包裹”,Spring Security 相当于“快递员”,三者结合,才能完成“安全授权”这个“快递任务”。
✅ 企业标准组合:Spring Security + OAuth2.0 + JWT,既能实现安全授权,又能适配分布式架构。
六、SpringBoot 整合 OAuth2.0 + JWT 实战
6.1 项目环境(提前准备)
-
SpringBoot 3.x(兼容 2.7.x)
-
JDK 11+
-
Maven 3.6+
-
Postman(用于测试接口)
6.2 引入核心依赖(pom.xml)
直接复制到 pom.xml 中,无需手动修改:
<dependencies>
<!-- Web 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Security 安全框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- OAuth2 资源服务 + JWT -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<!-- JWT 编解码依赖 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<!-- Lombok 简化代码(可选) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
6.3 配置文件(application.yml)
简化配置,测试用账号密码(后续可替换为数据库用户):
server:
port: 8080 # 项目端口
spring:
security:
user:
name: admin # 测试用户名
password: 123456 # 测试密码
roles: ADMIN # 测试角色(管理员)
6.4 JWT 配置(RSA非对称加密,安全!)
配置 JWT 的密钥、编码器、解码器,用 RSA 非对称加密(比对称加密更安全),直接复制:
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.UUID;
@Configuration
public class JwtConfig {
// 1. 生成 RSA 密钥对(非对称加密)
@Bean
public KeyPair keyPair() throws Exception {
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048); // 密钥长度 2048 位,足够安全
return generator.generateKeyPair();
}
// 2. 配置 JWK(JSON Web Key),用于 JWT 编解码
@Bean
public JWKSource<SecurityContext> jwkSource(KeyPair keyPair) {
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAKey rsaKey = new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString()) // 唯一密钥ID
.build();
JWKSet jwkSet = new JWKSet(rsaKey);
return new ImmutableJWKSet<>(jwkSet);
}
// 3. JWT 编码器(生成 Token)
@Bean
public JwtEncoder jwtEncoder(JWKSource<SecurityContext> jwkSource) {
return new NimbusJwtEncoder(jwkSource);
}
// 4. JWT 解码器(解析 Token)
@Bean
public JwtDecoder jwtDecoder(KeyPair keyPair) {
return NimbusJwtDecoder.withPublicKey((RSAPublicKey) keyPair.getPublic()).build();
}
}
6.5 Security + OAuth2 核心配置(认证+授权关键)
开启 OAuth2 资源服务,配置接口权限、无状态认证,直接复制:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity // 开启 Spring Security
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable() // 关闭 CSRF,前后端分离项目必关
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 无状态认证(不创建 session)
.and()
.authorizeRequests() // 配置接口权限
.requestMatchers("/auth/login").permitAll() // 登录接口放行,无需认证
.requestMatchers("/admin/**").hasRole("ADMIN") // /admin 开头的接口,只有 ADMIN 角色可访问
.requestMatchers("/user/**").hasRole("USER") // /user 开头的接口,只有 USER 角色可访问
.anyRequest().authenticated() // 其他所有接口,必须认证才能访问
.and()
.oauth2ResourceServer() // 开启 OAuth2 资源服务
.jwt(); // 使用 JWT 作为令牌
return http.build();
}
// 密码加密器(BCrypt 加密,安全不可逆)
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// 认证管理器(负责验证账号密码)
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
}
6.6 JWT 工具类(生成 Token,包含用户角色)
封装生成 JWT Token 的方法,将用户名、角色存入 Token,直接复制:
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.JwtEncoderParameters;
import org.springframework.stereotype.Component;
import java.time.Instant;
import java.util.stream.Collectors;
@Component
public class JwtUtil {
private final JwtEncoder encoder;
// 构造器注入 JwtEncoder
public JwtUtil(JwtEncoder encoder) {
this.encoder = encoder;
}
// 生成 JWT Token(包含用户名、角色)
public String generateToken(Authentication authentication) {
Instant now = Instant.now(); // 当前时间
// 获取用户角色(存入 Token,用于后续权限控制)
String roles = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(","));
// 构建 JWT 荷载(存储用户信息)
JwtClaimsSet claims = JwtClaimsSet.builder()
.issuer("http://localhost:8080") // 签发者(自己的项目地址)
.issuedAt(now) // 签发时间
.expiresAt(now.plusHours(1)) // 过期时间(1小时)
.subject(authentication.getName()) // 用户名
.claim("roles", roles) // 角色信息
.build();
// 生成 Token 并返回
return encoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();
}
}
6.7 登录接口(认证获取 Token)
用户登录,验证账号密码,生成并返回 JWT Token,直接复制:
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
@RequestMapping("/auth")
public class AuthController {
private final AuthenticationManager authenticationManager;
private final JwtUtil jwtUtil;
// 构造器注入
public AuthController(AuthenticationManager authenticationManager, JwtUtil jwtUtil) {
this.authenticationManager = authenticationManager;
this.jwtUtil = jwtUtil;
}
// 登录接口:POST 请求,参数为 username 和 password
@PostMapping("/login")
public Map<String, Object> login(
@RequestParam String username,
@RequestParam String password) {
// 1. 验证账号密码(由 Spring Security 自动验证)
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(username, password)
);
// 2. 验证通过,生成 JWT Token
String token = jwtUtil.generateToken(authentication);
// 3. 返回 Token 和类型(Bearer 类型)
return Map.of("token", token, "type", "Bearer");
}
}
6.8 测试接口(权限控制验证)
编写3个不同权限的接口,测试认证和授权是否生效,直接复制:
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
// 管理员接口:只有 ADMIN 角色可访问
@GetMapping("/admin/list")
public String admin(Authentication authentication) {
return "管理员专属接口:" + authentication.getName() + ",权限:ADMIN";
}
// 普通用户接口:只有 USER 角色可访问
@GetMapping("/user/info")
public String user() {
return "普通用户专属接口";
}
// 通用接口:只要登录(认证通过)即可访问
@GetMapping("/common")
public String common() {
return "登录即可访问的通用接口,认证成功!";
}
}
七、项目测试流程(Postman 实操)
代码写完后,用 Postman 测试:
7.1 登录获取 Token
-
打开 Postman,新建 POST 请求,地址:
http://localhost:8080/auth/login; -
请求参数(表单格式):
username=admin、password=123456; -
点击发送,返回结果如下(获取到 Token):
{
"token": "eyJhbGciOiJSUzI1NiJ9...", // 你的 Token(很长)
"type": "Bearer"
}
7.2 携带 Token 访问接口
-
新建 GET 请求(比如访问管理员接口),地址:
http://localhost:8080/admin/list; -
请求头添加:
Authorization: Bearer 你的Token(注意 Bearer 后面有一个空格); -
点击发送,成功返回结果(认证+授权通过);
-
测试其他接口:
-
访问
/user/info:返回 403 无权限(因为 admin 是 ADMIN 角色,没有 USER 角色); -
访问
/common:成功返回(登录即可访问); -
不携带 Token 访问任何接口:返回 401 未认证。
-
测试成功!说明OAuth2.0 + JWT 认证授权已经搭建完成。
八、核心知识点总结
-
OAuth2.0 是授权协议,JWT 是令牌格式,二者互补,不是替代关系;
-
OAuth2.0 四大角色:资源所有者、客户端、授权服务器、资源服务器;
-
企业常用授权模式:授权码模式(第三方登录)、密码模式(内部系统);
-
SpringBoot 整合核心三步:引入依赖 → 配置 Security + OAuth2 + JWT → 实现登录 + 权限控制;
-
OAuth2.0 + JWT 是企业级认证授权标准方案,适配分布式、前后端分离架构,必须掌握!
更多推荐



所有评论(0)