模拟服务器运行中
授权流程全链路测试
交互式模拟 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"]
}