Spring资源服务器Swagger-UI OAuth2授权码模式获取令牌失败
背景
部署了两个Spring应用:
- Spring Authorization Server:支持authorization_code流程(含PKCE),地址:
http://192.168.0.4:8001 - Spring资源服务器:提供账户CRUD接口,集成OpenAPI/Swagger,接收授权服务器颁发的令牌,地址:
http://192.168.0.4:8002
问题现象
Swagger-UI获取授权码后,调用/oauth2/token交换access_token时触发CORS错误:
Access to fetch at 'http://192.168.0.4:8001/oauth2/token' from origin 'http://192.168.0.4:8002' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
排查发现:Swagger-UI发起的令牌交换请求未携带Cookie和Basic Auth头,而这两类信息是授权服务器维持状态必需的。Postman测试authorization_code(含PKCE)流程正常,但Swagger-UI无法完成令牌交换。
预期正常的令牌交换请求示例:
curl --location 'http://192.168.100.102:8001/oauth2/token' \ --header 'Content-Type: application/x-www-form-urlencoded' \ --header 'Authorization: Basic Y2xpZW50OnNlY3JldA==' \ --data-urlencode 'grant_type=authorization_code' \ --data-urlencode 'client_id=client' \ --data-urlencode 'redirect_uri=http://192.168.0.4:8002/swagger-ui/oauth2-redirect.html' \ --data-urlencode 'code=S-yW9-fNexepByQEvWnr5MLMSO8YAtX1npBp7VUEF3FAo-YqljVbVGGuf1eIa8kpJnviZXGzsgM59HJlULJc5nHI1blWbcxG7xINm7FpVkcG0zxQKdWBUSxsADy23bKD'
解决方案
1. 修复授权服务器CORS配置
授权服务器的/oauth2/token接口需正确处理跨域预检请求(OPTIONS),禁止在预检请求中返回重定向。添加以下配置:
CORS过滤器配置
@Configuration public class CorsConfig { @Bean public CorsFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.addAllowedOrigin("http://192.168.0.4:8002"); config.setAllowCredentials(true); config.addAllowedMethod("*"); config.addAllowedHeader("*"); config.addExposedHeader("Authorization"); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/oauth2/**", config); source.registerCorsConfiguration("/login/**", config); return new CorsFilter(source); } }
Spring Security放行OPTIONS请求
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .cors(Customizer.withDefaults()) .authorizeHttpRequests(auth -> auth .requestMatchers(HttpMethod.OPTIONS, "/oauth2/**").permitAll() .anyRequest().authenticated() ); return http.build(); } }
2. 调整Swagger-UI OAuth2配置
确保Swagger-UI在令牌交换时携带Basic Auth头和Cookie:
@Configuration @OpenAPIDefinition(info = @Info(title = "账户API", version = "v1")) public class OpenApiConfig { @Bean public OpenAPI customOpenAPI() { return new OpenAPI() .components(new Components() .addSecuritySchemes("oauth2", new SecurityScheme() .type(SecurityScheme.Type.OAUTH2) .flows(new OAuthFlows() .authorizationCode(new OAuthFlow() .authorizationUrl("http://192.168.0.4:8001/oauth2/authorize") .tokenUrl("http://192.168.0.4:8001/oauth2/token") .scopes(new Scopes() .addString("account:read", "读取账户") .addString("account:write", "修改账户") ) .extensions(Map.of("useBasicAuthenticationWithAccessCodeGrant", true)) ) ) ) ) .addSecurityItem(new SecurityRequirement().addList("oauth2")); } @Bean public UiConfiguration uiConfig() { return UiConfigurationBuilder.builder() .oauth2RedirectUrl("http://192.168.0.4:8002/swagger-ui/oauth2-redirect.html") .withCredentials(true) .build(); } }
3. 检查重定向脚本
使用Swagger-UI默认的oauth2-redirect.html,不要自定义修改请求逻辑,避免阻止Cookie或请求头的携带。
4. 验证PKCE配置
确保授权服务器客户端配置开启PKCE支持:
@Configuration @EnableAuthorizationServer public class AuthorizationServerConfig { @Bean public RegisteredClientRepository registeredClientRepository() { RegisteredClient client = RegisteredClient.withId(UUID.randomUUID().toString()) .clientId("client") .clientSecret("{noop}secret") .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC) .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .redirectUri("http://192.168.0.4:8002/swagger-ui/oauth2-redirect.html") .scope("account:read") .scope("account:write") .clientSettings(ClientSettings.builder().requireProofKey(true).build()) .build(); return new InMemoryRegisteredClientRepository(client); } }
内容的提问来源于stack exchange,提问作者S34N
相关产品推荐
相关产品推荐

