/ 仪表盘
模拟服务器运行中

授权流程全链路测试

交互式模拟 Spring Authorization Server 的 OAuth 2.1 核心授权流程,每一步展示真实 HTTP 请求与响应。

测试流程
4
授权码 / PKCE / 客户端凭证 / 刷新
端点覆盖
5
Authorize / Token / UserInfo / JWK / Introspection
协议版本
2.1
OAuth 2.1 + OIDC 1.0
已执行步数
0
本次会话累计
快速开始
选择左侧任意流程,逐步模拟执行
核心架构
资源拥有者
Resource Owner
授权服务器
Spring Auth Server
/oauth2/authorize/oauth2/token
客户端应用
资源服务器
Authorization CodeRFC 6749 §4.1

授权码模式

最完整安全的 OAuth 授权流程。客户端先获取授权码,再用授权码交换令牌。适用于有后端的 Web 应用。

用户
客户端
授权服务器
步骤 0 / 6
PKCE (S256)RFC 7636

PKCE 授权码扩展

为公共客户端(SPA、移动端)提供额外安全保护。通过 code_challenge/code_verifier 防止授权码拦截。OAuth 2.1 已将其设为必选。

PKCE 原理:verifier 客户端生成 → challenge=SHA256(verifier) → 授权请求带 challenge → Token请求带 verifier → 服务端比对
SPA / App
授权服务器
步骤 0 / 6
Client CredentialsRFC 6749 §4.4

客户端凭证模式

无用户参与,客户端以自身身份直接获取令牌。适用于机器间通信(M2M)、后台服务调用等场景。

客户端
授权服务器
步骤 0 / 3
Refresh TokenRFC 6749 §6

刷新令牌

当 access_token 过期时,使用 refresh_token 获取新的 access_token(以及新的 refresh_token),实现无感续期。OAuth 2.1 要求刷新令牌必须绑定客户端。

客户端
资源服务器
授权服务器
步骤 0 / 5

Spring Authorization Server 配置

基于 SAS 1.x / 2.x 的最小化可运行配置,覆盖注册客户端、授权服务器核心参数。

SecurityConfig.java
授权服务器核心配置类
SecurityConfig.java
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/login", "/.well-known/**").permitAll() .anyRequest().authenticated() ) .oauth2ResourceServer(oauth2 -> oauth2 .jwt(Customizer.withDefaults()) ) .formLogin(form -> form .loginPage("/login").permitAll() ); return http.build(); } }
AuthorizationServerConfig.java
注册客户端 + 端点配置
AuthorizationServerConfig.java
@Configuration public class AuthorizationServerConfig { // 注册客户端 @Bean public RegisteredClientRepository registeredClientRepository() { var loginClient = RegisteredClient.withId(UUID.randomUUID().toString()) .clientId("login-client") .clientSecret("{noop}secret") .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC) .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN) .redirectUri("http://127.0.0.1:8080/login/oauth2/code/login-client") .scope("openid").scope("profile").scope("read") .clientSettings(ClientSettings.builder() .requireAuthorizationConsent(true) // 需要用户同意 .requireProofKey(false) // 可选开启 PKCE .build()) .tokenSettings(TokenSettings.builder() .accessTokenTimeToLive(Duration.ofMinutes(30)) .refreshTokenTimeToLive(Duration.ofDays(7)) .reuseRefreshTokens(false) // OAuth 2.1 推荐 false .build()) .build(); var m2mClient = RegisteredClient.withId(UUID.randomUUID().toString()) .clientId("m2m-client") .clientSecret("{noop}secret") .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC) .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS) .scope("read").scope("write") .build(); return new InMemoryRegisteredClientRepository(loginClient, m2mClient); } @Bean public AuthorizationServerSettings authServerSettings() { return AuthorizationServerSettings.builder() .issuer("http://localhost:9000") .build(); } @Bean public JWKSource<JWKContext> jwkSource() { var keyPair = generateRsaKey(); var jwkSet = new JWKSet(new RSAKey.Builder(keyPair.getPublic()) .keyID(UUID.randomUUID().toString()).build()); return (jwkSelector, context) -> jwkSelector.select(jwkSet); } }
application.yml
最小化配置
application.yml
server: port: 9000 spring: security: user: name: user password: password roles: USER

端点一览

Spring Authorization Server 默认暴露的所有 OAuth 2.1 / OIDC 端点。

方法路径说明
GET/oauth2/authorize授权端点
POST/oauth2/token令牌端点
POST/oauth2/introspect令牌内省
POST/oauth2/revoke令牌撤销
POST/oauth2/device_authorization设备授权
GET/oauth2/device_verification设备验证
GET/.well-known/openid-configurationOIDC 发现
GET/.well-known/oauth-authorization-serverAS 元数据
GET/userinfo用户信息
GET/oauth2/jwksJSON Web Key Set
GET/login登录页
POST/login登录提交
GET/oauth2/consent同意页
Discovery 文档示例
GET /.well-known/oauth-authorization-server 响应
{ "issuer": "http://localhost:9000", "authorization_endpoint": "http://localhost:9000/oauth2/authorize", "token_endpoint": "http://localhost:9000/oauth2/token", "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post"], "introspection_endpoint": "http://localhost:9000/oauth2/introspect", "revocation_endpoint": "http://localhost:9000/oauth2/revoke", "jwks_uri": "http://localhost:9000/oauth2/jwks", "response_types_supported": ["code"], "grant_types_supported": ["authorization_code", "client_credentials", "refresh_token"], "code_challenge_methods_supported": ["S256"], "scopes_supported": ["openid", "profile", "read", "write"] }