Spring Boot OAuth2 授权码模式开发实战

一、核心概念解析

在进行开发前,先明确OAuth2核心组件、表单登录的适配逻辑及Spring Boot默认开放端点信息,避免概念混淆:

1.1 OAuth2核心组件

  • 授权服务(Authorization Server):OAuth2的核心组件,负责颁发访问令牌(Access Token)、刷新令牌(Refresh Token),验证客户端身份,处理授权请求(如授权码模式、密码模式等)。

  • 资源服务(Resource Server):存储受保护资源的服务,接收客户端的资源请求时,需验证请求携带的Access Token的合法性,只有验证通过才允许访问资源。

  • 客户端(Client):请求访问资源的应用,需在授权服务注册,拥有唯一的client_id和client_secret,用于身份认证。

  • 表单登录(Form Login):OAuth2默认支持多种授权模式,表单登录是适配Web应用的常用方式,用户通过用户名密码表单完成身份认证,进而获取授权。

更详细的oauth2知识总结,点击查看文章【OAuth 2.0 超详细总结】

1.2 Spring Boot 默认开放端点说明

Spring Boot 结合 Spring Security、OAuth2 Authorization Server 时,会默认开放一系列核心端点,用于完成授权流程、令牌管理等核心操作,无需额外编码配置,具体分类及说明如下:

1.2.1 OAuth2 授权服务核心端点

  • /oauth2/authorize:授权端点,用于接收客户端的授权请求,引导用户完成身份认证与授权确认(核心端点)。

  • /oauth2/token:令牌端点,用于客户端通过授权码、客户端凭证等方式兑换 Access Token、Refresh Token。

  • /oauth2/revoke:令牌撤销端点,用于客户端主动撤销已颁发的 Access Token 或 Refresh Token。

  • /oauth2/introspect:令牌 introspect 端点,用于验证令牌的合法性、有效性及相关元信息(如令牌范围、过期时间等)。

1.2.2 OIDC 相关默认端点(启用OIDC后开放)

当在授权服务配置中启用 OIDC(OpenID Connect)后,会额外开放以下端点,用于支持用户信息获取、ID Token 相关操作:

  • /userinfo:用户信息端点,客户端可通过此端点获取当前登录用户的基本信息(如用户名、角色等),需携带有效的 Access Token。

  • /.well-known/openid-configuration:OIDC 发现端点,返回授权服务的元信息(如各端点地址、支持的算法、版本等),供客户端自动适配配置。

  • /oidc/jwks:JWKS(JSON Web Key Set)端点,返回用于验证 ID Token 签名的公钥信息。

1.2.3 Spring Security 表单登录默认端点

  • /login:表单登录端点,未自定义登录页面时,Spring Security 会提供默认登录页面,支持 GET(获取登录页)和 POST(提交登录信息)请求。

  • /logout:注销端点,支持 POST 请求,用于用户退出登录,清除会话信息。

1.2.4 其他默认端点

  • /error:错误处理端点,当系统发生异常(如认证失败、授权拒绝等)时,会默认跳转到该端点返回错误信息。

二、环境准备

本指南采用「授权服务与资源服务可合并部署」的架构,分为客户端和服务端两个项目,三方登录额外配置了Gitee登录(需可访问的外网域名)。

2.1 基础依赖

2.1.1 授权服务与资源服务依赖

xml 复制代码
<properties>
        <java.version>21</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>3.3.5</spring-boot.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- Spring Boot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Spring Boot Security -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <!-- Spring Boot OAuth2 Resource Server -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
        </dependency>
        
        <!-- Spring Security OAuth2 Authorization Server -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-oauth2-authorization-server</artifactId>
        </dependency>

    </dependencies>

2.1.2 客户端依赖

xml 复制代码
 <properties>
        <java.version>21</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>3.3.5</spring-boot.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <!-- Spring Boot Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Spring Boot Security -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <!-- Spring Boot OAuth2 Client -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-client</artifactId>
        </dependency>
       
        <!-- Spring Boot Test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

2.2 端口规划

为避免端口冲突,明确两个服务的端口配置:

  • 授权服务与资源服务:端口 8081

  • 客户端:端口 8080

三、授权与资源服务开发(核心步骤)

3.1 核心配置类

创建 SecurityConfig 类,整合 OAuth2 授权服务配置,OAuth2 资源服务配置与 Spring Security 表单登录配置:

java 复制代码
package com.example.auth2.config;

import java.io.IOException;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.oidc.OidcUserInfo;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.util.matcher.RequestMatcher;

import com.example.auth2.controller.ApiController;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

/**
 * Spring Security配置类 配置OAuth2安全链,包括: 1. 资源服务器:保护API端点,支持Bearer令牌认证
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);

    @Autowired
    ApiController apiController;

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return web -> web.ignoring()
                // 忽略所有静态资源
                .requestMatchers("/css/**", "/js/**", "/images/**", "/static/**", "/public/**", "/webjars/**", "/resources/**", "/favicon.ico", "/robots.txt");
    }

    @Bean
    @Order(2) 
    public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
        // 应用OAuth2授权服务器的默认安全规则(核心)
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
        http
                // 配置OIDC相关端点的安全规则(关键:显式启用OIDC)
                .getConfigurer(OAuth2AuthorizationServerConfigurer.class).oidc(oidc -> oidc.userInfoEndpoint(userInfo -> userInfo
                        // 可选:配置用户信息端点的自定义处理器(如需扩展用户信息)
                        .userInfoMapper(userDetails -> {
                            // 自定义ID Token和UserInfo响应中的字段映射
                            return new OidcUserInfo(apiController.getUserInfoOidc());
                        })));
        http.requestCache(cache -> cache.requestCache(chromeSafeRequestCache())).csrf(csrf -> csrf.disable())
                // 确保未认证用户访问授权端点时重定向到登录页面
                .exceptionHandling(exceptions -> exceptions.authenticationEntryPoint((request, response, authException) -> {
                    response.sendRedirect("/login");
                }));

        return http.build();
    }

    @Bean
    @Order(3) 
    public SecurityFilterChain resourceServerSecurityFilterChain(HttpSecurity http) throws Exception {

        http.securityMatcher("/api/**").authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated()).oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> {
        })).sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)).csrf(csrf -> csrf.disable());

        return http.build();
    }

    @Bean
    @Order(4) 
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {

        http.securityMatcher(new RequestMatcher() {
            @Override
            public boolean matches(HttpServletRequest request) {
                // 明确排除API路径
                return !request.getRequestURI().startsWith("/api/");
            }
        })
                // 配置所有请求都需要认证
                .authorizeHttpRequests(authz -> authz
                        // 允许访问首页
                        .requestMatchers("/", "/login", "/error").permitAll()
                        // 其他请求都需要认证
                        .anyRequest().authenticated())
                // 使用默认表单登录
                .formLogin(formLogin -> formLogin.defaultSuccessUrl("/", false)).requestCache(cache -> cache.requestCache(chromeSafeRequestCache()))
                // 配置注销
                .logout(logout -> logout.logoutSuccessUrl("/"))
                // 测试环境关闭HTTPS要求(生产环境必须开启HTTPS)
                .requiresChannel(channel -> channel.anyRequest().requiresInsecure())
                // 使用Spring Security的默认异常处理
                .csrf(csrf -> csrf.disable());

        return http.build();
    }

    /**
     * 授权服务器设置
     */
    @Bean
    public AuthorizationServerSettings authorizationServerSettings() {
        return AuthorizationServerSettings.builder().issuer("http://localhost:8081").build();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user = User.withUsername("admin").password(passwordEncoder().encode("123456")).roles("ADMIN").build();
        return new InMemoryUserDetailsManager(user);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public RequestCache chromeSafeRequestCache() {
        return new HttpSessionRequestCache() {
            @Override
            public void saveRequest(HttpServletRequest request, HttpServletResponse response) {
                String uri = request.getRequestURI();
                String query = request.getQueryString();

                // 排除 Chrome DevTools 相关的请求
                if (uri != null && uri.contains("/.well-known/appspecific/")) {
                    return; // 不保存这个请求
                }

                // 只保存重要的请求
                if (uri != null && !uri.contains("/.well-known/")) {
                    super.saveRequest(request, response);
                }
            }
        };
    }

    @Bean
    public FilterRegistrationBean<Filter> traceIdFilter() {
        Filter filter = new Filter() {
            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
                // 生成唯一的traceid
                String traceId = UUID.randomUUID().toString();
                // 将traceid存储到MDC中
                MDC.put("traceid", traceId);
                try {
                    // 继续处理请求
                    chain.doFilter(request, response);
                } finally {
                    // 请求处理完成后,清除MDC中的traceid
                    MDC.remove("traceid");
                }
            }
        };
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
        registration.setFilter(filter);
        registration.addUrlPatterns("/*");
        registration.setOrder(Ordered.HIGHEST_PRECEDENCE); // 确保最先执行
        registration.setName("traceIdFilter");
        return registration;
    }

}

配置客户端存储

java 复制代码
package com.example.auth2.config;

import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;

/**
 * OAuth2授权服务器配置
 * 配置客户端注册
 */
@Configuration
public class AuthorizationServerConfig {

    private static final Logger logger = LoggerFactory.getLogger(AuthorizationServerConfig.class);

    @Autowired
    PasswordEncoder passwordEncoder; 
    /**
     * 配置客户端注册存储
     * 这里使用内存存储,生产环境建议使用数据库存储
     */
    @Bean
    public RegisteredClientRepository registeredClientRepository() {
          // 1. 对客户端密钥进行BCrypt加密(核心修复点)
        String plainClientSecret = "test-secret";
        String encryptedClientSecret = passwordEncoder.encode(plainClientSecret);
        // 创建一个模拟客户端,用于测试
        RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
                .clientId("test-client")
                .clientSecret(encryptedClientSecret)
                .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .redirectUri("http://localhost:8080/login/oauth2/code/self")
                .scope("user_info")
                .scope(OidcScopes.OPENID)
                .clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
                .build();

        logger.info("OAuth2授权服务器:已注册客户端,client_id: test-client, client_secret: test-secret");
        return new InMemoryRegisteredClientRepository(registeredClient);
    }
}

3.2 关键配置说明

  • 密码加密器:使用 BCryptPasswordEncoder,Spring Security 5.x 后不允许明文密码,必须配置加密器。

  • 用户详情服务:此处用内存用户(InMemoryUserDetailsManager),实际开发需替换为 JdbcUserDetailsManager 或自定义 UserDetailsService,从数据库查询用户信息。

  • 客户端配置:客户端需注册 clientId、clientSecret、重定向URI、授权模式等信息,此处用内存存储,实际开发需持久化到数据库(可使用 JdbcRegisteredClientRepository)。

  • 表单登录:未自定义登录页面时,Spring Security 会提供默认的表单登录页面(访问 /login 即可看到),如需自定义登录页面,可通过 http.formLogin().loginPage("/custom-login") 配置。

3.3 启动服务

创建授权服务启动类,直接启动即可:

java 复制代码
package com.example.auth2;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Spring Boot主类
 * 登录OAuth2.0示例项目入口
 */
@SpringBootApplication
public class Auth2ServerApplication {

    private static final Logger logger = LoggerFactory.getLogger(Auth2ServerApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(Auth2ServerApplication.class, args);
        logger.info("Spring Security OAuth2.0 服务端示例项目启动成功");
    }

}

启动成功后,访问 http://localhost:8081/login 可看到默认的表单登录页面,输入 admin/123456 可登录。

四、客户端开发(核心步骤)

4.1 核心配置类

java 复制代码
package com.example.auth2.config;

import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;

/**
 * Spring Security配置类
 * 配置OAuth2安全链,包括:
 * 客户端登录:支持Gitee OAuth2登录
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return web -> web.ignoring()
            // 忽略所有静态资源
            .requestMatchers(
                "/css/**",
                "/js/**", 
                "/images/**",
                "/static/**",
                "/public/**",
                "/webjars/**",
                "/resources/**",
                "/favicon.ico",
                "/robots.txt"
            );
    }
    /**
     * 配置SecurityFilterChain,实现基本的OAuth2安全链
     * 简化配置,只保留必要的功能,避免兼容性问题
     * 
     * @param http HttpSecurity
     * @return SecurityFilterChain
     * @throws Exception 异常
     */
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                // 配置授权请求
                .authorizeHttpRequests(authorize -> authorize
                        // 允许公开访问的端点
                        .requestMatchers("/", "/thirdlogin", "/error").permitAll()
                        // 其他请求需要认证
                        .anyRequest().authenticated())
                // 配置OAuth2客户端登录(Gitee和Self登录)
                .oauth2Login(oauth2 -> oauth2
                        .loginPage("/thirdlogin")
                        .successHandler(oauth2LoginSuccessHandler())) // 绑定成功处理器
                .logout(logout -> logout
                        .logoutSuccessUrl("/"))
                .csrf(csrf -> csrf.disable());

        logger.info("Spring Security配置完成,已启用:");
        return http.build();
    }

     // ========== 1. 自定义登录成功处理器(固定跳转) ==========
    @Bean
    public AuthenticationSuccessHandler oauth2LoginSuccessHandler() {
        // 方案1:固定跳转至 /user 页面
        SimpleUrlAuthenticationSuccessHandler successHandler = new SimpleUrlAuthenticationSuccessHandler() {
            @Override
            public void onAuthenticationSuccess(jakarta.servlet.http.HttpServletRequest request,
                                                jakarta.servlet.http.HttpServletResponse response,
                                                Authentication authentication) throws IOException, jakarta.servlet.ServletException {
                // 核心:指定固定跳转URL
                this.setDefaultTargetUrl("/user");
                // 可选:清除登录前的请求缓存(避免跳回原页面)
                this.setAlwaysUseDefaultTargetUrl(true);
                super.onAuthenticationSuccess(request, response, authentication);
            }
        };
        return successHandler;
    }
   
}

4.2 配置文件(application.yml)

配置client信息和服务端信息,添加如下配置:

yaml 复制代码
spring:
  application:
    name: spring-security-auth2
  profiles:
    active: dev
  # OAuth2配置
  security:
    oauth2:
      # 客户端配置(Gitee登录)
      client:
        registration:
          gitee:  # 自定义注册ID,需与回调地址中的code/后字段一致
            client-id: fad0a078e71e4e20c7739f83bcc4c61a6ec182bcb8beaa6437446c75ee8fcc1b  # 替换为实际值
            client-secret: 0d0dbb79810d867dc36e173e5a2a161075a2094f525a8bd2dccfa3daeaf53cbc  # 替换为实际值
            authorization-grant-type: authorization_code
            redirect-uri: "http://wangmoon.zicp.fun/login/oauth2/code/gitee"
            scope: user_info  # Gitee的授权范围,获取用户信息
            client-name: Gitee
          # 配置指向自己应用程序的客户端注册
          self:  # 自定义注册ID,指向自己的应用程序
            client-id: test-client  # 使用之前配置的测试客户端ID
            client-secret: test-secret  # 使用之前配置的测试客户端密钥
            authorization-grant-type: authorization_code
            redirect-uri: "http://localhost:8080/login/oauth2/code/self"
            scope: user_info,openid  # 授权范围,用户信息
            client-name: Self OAuth2 Provider
        provider:
          gitee:  # 配置Gitee的OAuth端点
            authorization-uri: https://gitee.com/oauth/authorize
            token-uri: https://gitee.com/oauth/token
            user-info-uri: https://gitee.com/api/v5/user
            user-name-attribute: login  # Gitee用户信息中唯一标识字段(login是用户名)
          # 配置另一个提供者为自己的应用程序
          self:  # 自定义提供者ID,指向自己的应用程序
            issuer-uri: http://localhost:8081
server:
  port: 8080
  servlet:
    context-path: /
    session:
      cookie:
        name: APP_SESSION

五、表单登录 + OAuth2 授权流程测试

本测试采用「授权码模式」,完整流程为:客户端(浏览器)请求资源 → 跳转授权服务表单登录 → 登录成功后授权 → 获取授权码 → 兑换 Access Token → 访问资源。

5.1 测试步骤

  1. 访问资源服务的受保护接口:打开浏览器,访问 http://localhost:8080/user)。

  2. 跳转表单登录:因未登录,会自动跳转到登录页面(http://localhost:8080/thirdlogin)。

  3. 选择三方登录方式:self方式或gitee(需要外网域名)

  4. 授权服务端用户登录:输入用户名 admin,密码 123456,点击登录。

  5. 授权确认:登录成功后,授权服务会询问用户是否允许客户端(web-client)访问资源,勾选user_info,点击「提交」。

  6. 获取授权码并兑换令牌:授权服务会将授权码通过重定向URI请求资源服务,资源服务自动用授权码向授权服务兑换 Access Token。

  7. 访问资源成功:客户端使用令牌验证通过后,获取用户信息成功后跳转到/user页面

六、常见问题与注意事项

  1. 授权服务,资源服务,表单登录合并部署要配置好securityMatcher,避免相互覆盖
  2. 只有第一个匹配到 SecurityFilterChain 会被处理,其他的会忽略
  3. 授权服务,资源服务,表单登录要分为三个 SecurityFilterChain 分别配置
  4. 客户端配置:issuer-uri 配了后会自动调用发现端点 /.well-known/openid-configuration,获取 token,授权,oidc用户信息等调用地址信息,否则需手动配置这些地址:authorization-uri,token-uri,user-info-uri

七、总结

本文覆盖了 Spring Boot OAuth2 授权服务、资源服务的开发流程,以及表单登录的集成方式,核心在于理解 OAuth2 的授权流程和 Spring Security 的权限控制逻辑。开发过程中需重点关注依赖版本匹配、令牌验证一致性、权限规则配置三大核心点,同时根据实际需求调整用户存储、客户端存储、表单登录页面等细节。

项目源码,进主页资源下载

相关推荐
赵得C2 小时前
完整 Oracle 12c 分页 Demo(Spring Boot+MyBatis+PageHelper)
spring boot·oracle·mybatis
中科天工2 小时前
智能仓储解决方案到底是什么?
大数据·人工智能·智能
xl-xueling2 小时前
从快手直播故障,看全景式业务监控势在必行!
大数据·后端·网络安全·流式计算
AI题库2 小时前
PostgreSQL 18 从新手到大师:实战指南 - 1.1 PostgreSQL 18简介
数据库·postgresql
好记忆不如烂笔头abc2 小时前
Ubuntu 20.04.6上实现远程桌面连接
服务器·网络·数据库
今晚务必早点睡2 小时前
Redis——快速入门第七课:Redis 为什么这么快?
数据库·redis·缓存
EterNity_TiMe_3 小时前
从 0 到 1:Llama 3-8B 在昇腾 Atlas 800T 上的推理调优与算力榨干指南
数据库·llama·昇腾·atlas 800t·实战部署
云老大TG:@yunlaoda3603 小时前
华为云国际站代理商运维保障的具体要求有哪些?
大数据·运维·华为云
Nautiluss3 小时前
一起调试XVF3800麦克风阵列(二)
大数据·人工智能·嵌入式硬件·音频·语音识别·dsp开发