导读:本期聚焦于云朵创作的《Spring Boot 如何整合 Spring Security OAuth2 实现授权认证?》,敬请观看详情。当系统需要支持第三方登录、单点登录或者为多个微服务提供统一的认证入口时,OAuth2 协议几乎是绕不开的选择。本文围绕 Spring Boot 整合 Spring Security OAuth2 展开讲解,先说明授权码模式的整体流程与授权服务器、资源服务器的职责划分,再通过完整的依赖配置和代码示例,演示如何搭建授权服务器、生成 token、保护资源接口,以及配置客户端信息与 token 存储方式。文中还对比了 JWT 与内存、Redis 存储 token 的优缺点,并给出常见报错和调试思路,帮助你快速落地一套可用的 OAuth2 授权体系。

OAuth2 是目前最主流的授权协议,无论是第三方登录、开放平台对接,还是微服务体系中的统一认证中心,都离不开它。Spring 生态对 OAuth2 的支持经历了从官方的 Spring Security OAuth2 到 Spring Authorization Server 的演变过程,网络上的资料新旧混杂,很多人照着旧教程配置发现类都找不到。本文将以目前主流的 Spring Boot 版本为基础,完整演示如何搭建一个授权服务器和资源服务器,走通整个授权码流程。

Spring Boot 如何整合 Spring Security OAuth2 实现授权认证?

一、理解 OAuth2 的角色与授权码流程

在动手写代码之前,必须先搞清楚 OAuth2 的四个角色:资源所有者(通常是用户)、客户端(第三方应用)、授权服务器(负责发放 token)和资源服务器(负责校验 token 并提供受保护的 API)。很多人把授权服务器和资源服务器混为一谈,实际上它们完全可以是两个独立的 Spring Boot 应用,在微服务架构中通常也是分开部署的。

以最常见的授权码模式为例,整个流程是:用户访问客户端应用,客户端把用户重定向到授权服务器的登录页面;用户完成认证并同意授权后,授权服务器返回一个授权码给客户端;客户端拿着授权码去换取 access_token;之后客户端每次请求资源服务器的接口时都携带这个 token,资源服务器校验通过后返回数据。这个过程看起来环节不少,但 Spring Security 已经帮我们封装了绝大部分逻辑,真正需要开发者做的,主要是配置客户端信息、用户信息以及 token 的处理方式。

另外要注意,旧版 Spring Security OAuth2 中的 @EnableAuthorizationServer 注解在 Spring Security 5 之后已经被废弃,官方推出了新的 Spring Authorization Server 项目作为替代。如果你在老项目里看到这些注解,不要直接照搬到新项目中,版本差异是踩坑的重灾区。

二、搭建授权服务器并生成 Token

首先创建一个 Spring Boot 项目,引入 Spring Authorization Server 的依赖。以 Maven 为例,核心依赖如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId;spring-boot-starter-web</artifactId>
</dependency>
&ltlt;dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId;spring-security-oauth2-authorization-server</artifactId>
    <version>0.4.3</version>
</dependency>

注意上面第二段依赖标签的写法,实际使用时请保证标签完整。接下来是核心的配置类,我们需要注册客户端信息、配置 token 签发策略,并提供一个测试用的用户:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public RegisteredClientRepository registeredClientRepository() {
        RegisteredClient client = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("demo-client")
                .clientSecret("{noop}demo-secret")
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .redirectUri("http://127.0.0.1:8081/login/oauth2/code/demo")
                .scope(OidcScopes.OPENID)
                .scope("read")
                .build();
        return new InMemoryRegisteredClientRepository(client);
    }

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user = User.withDefaultPasswordEncoder()
                .username("admin")
                .password("123456")
                .roles("USER")
                .build();
        return new InMemoryUserDetailsManager(user);
    }
}

这段配置里有几个关键点需要说明。clientId 和 clientSecret 是客户端应用在授权服务器上注册时获得的身份凭证,redirectUri 必须和客户端配置的回调地址完全一致,哪怕多一个斜杠都会报 redirect_uri mismatch 错误。clientSecret 前面的 {noop} 表示密码不加密存储,仅用于本地测试,生产环境一定要换成 {bcrypt} 加密方式。

还需要一个授权服务器的核心配置类,用于指定 token 的签发端点和签名密钥:

@Bean
@Order(1)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
    OAuth2AuthorizationServerConfiguration.applyDefaultConfiguration(http, applicationContext);
    http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
            .oidc(Customizer.withDefaults());
    http.exceptionHandling(e -> e.defaultAuthenticationEntryPointFor(
            new LoginUrlAuthenticationEntryPoint("/login"),
            new MediaTypeRequestMatcher(MediaType.TEXT_HTML)));
    return http.build();
}

配置完成后启动应用,浏览器访问 http://127.0.0.1:8080/oauth2/authorize?response_type=code&client_id=demo-client&scope=read,输入 admin 和 123456 登录后即可拿到授权码,再通过 token 端点用授权码换取 access_token,整个授权码流程就走通了。

三、搭建资源服务器保护 API 接口

资源服务器的职责是校验 token 并暴露受保护的接口。单独创建一个 Spring Boot 项目,端口设为 8082,引入 spring-boot-starter-oauth2-resource-server 依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId;spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

然后在配置文件中指定授权服务器提供的 issuer 地址,资源服务器会自动去该地址获取公钥并校验 JWT 格式的 token:

server:
  port: 8082
spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: http://127.0.0.1:8080

最后写一个简单的测试接口,并在安全配置中要求所有请求都必须认证:

@RestController
public class UserController {

    @GetMapping("/api/user")
    public Map<String, Object> getUser() {
        Map<String, Object> result = new HashMap<>();
        result.put("id", 1);
        result.put("name", "admin");
        return result;
    }
}

@Configuration
@EnableWebSecurity
public class ResourceServerConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
            .oauth2ResourceServer(oauth2 -> oauth2.jwt());
        return http.build();
    }
}

测试时先请求 token,再携带 token 访问接口。token 过期后资源服务器会返回 401,这时客户端可以用 refresh_token 重新获取,无需用户再次登录,这就是 OAuth2 体验优于传统 session 方案的地方之一。

四、Token 存储方案的选择

Token 怎么存是个绕不开的话题,常见的有三种方案。第一种是内存存储,即 InMemoryTokenStore,配置最简单,重启后 token 全部失效,只适合学习和演示。第二种是 Redis 存储,token 集中保存在 Redis 中,资源服务器每次校验都要查询一次 Redis,好处是可以主动吊销某个 token,用户改密码或被封禁后能立即生效,适合传统单体或对注销功能有强需求的场景。

第三种是目前微服务架构下最主流的 JWT 方案。token 本身携带了用户信息并附带签名,资源服务器本地用公钥就能完成校验,不需要每次都去查询存储介质,性能好、天然无状态、方便水平扩展。代价是 token 一旦签发就无法主动作废,只能等它自然过期,通常的做法是缩短 access_token 的有效期(比如两小时),配合较长的 refresh_token 使用。另外 JWT 的 payload 只是 Base64 编码而非加密,绝对不要往里面塞手机号、身份证号这类敏感信息。

简单来说,如果你的系统需要强制下线能力,选 Redis;如果是无状态的微服务体系,选 JWT,两者也可以结合使用。技术选型没有绝对的好坏,关键是理解每种方案的取舍。

五、常见问题与调试建议

整合过程中最容易遇到的几个报错值得单独说一下。redirect_uri_mismatch 说明回调地址和注册的不一致,逐字符比对即可;invalid_grant 通常出现在换 token 阶段,常见原因是授权码已被使用过或已过期,授权码默认一次性且有效期很短;返回 401 则要检查请求头是否正确携带了 Authorization: Bearer xxx 格式的 token,注意 Bearer 和 token 之间有个空格。

调试时建议开启 Spring Security 的调试日志,在配置文件中加入 logging.level.org.springframework.security=DEBUG,可以清楚看到过滤器链的处理过程和认证失败的具体原因。另外用 Postman 或 curl 直接请求 token 端点比走浏览器更直观,能快速定位问题出在客户端凭证、用户认证还是 token 签发环节。只要把授权码模式的流程理解透,其他客户端凭证模式、密码模式、设备码模式都只是同一套框架下的不同 grant type 配置而已。

Spring BootOAuth2授权认证修改时间:2026-09-10 05:54:35

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260910/53852.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。