如何通过Spring Security追踪OAuth2服务器查询及调试令牌转换?
问题解决:OAuth2日志不输出及自定义OidcUserService未触发
一、解决OAuth2与Keycloak交互的日志输出问题
当前日志配置仅覆盖了org.springframework.security.oauth2,无法完整捕获与Keycloak之间的HTTP请求细节,需补充以下配置:
1. 调整日志级别配置
更新application.yml的日志部分,添加HTTP客户端、OAuth2客户端全链路的TRACE级别日志:
logging: level: org.springframework.web.client.RestTemplate: TRACE org.springframework.security.oauth2.client: TRACE org.springframework.security.oauth2.client.registration: TRACE org.springframework.security.oauth2.client.web: TRACE org.springframework.security.oauth2.core: TRACE # 保留原有配置 org.springframework.web.filter.CommonsRequestLoggingFilter: DEBUG org.springframework.security.oauth2: TRACE
2. 启用CommonsRequestLoggingFilter
仅设置日志级别不会自动启用该过滤器,需手动注册Bean以捕获请求/响应内容:
@Bean public CommonsRequestLoggingFilter requestLoggingFilter() { CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter(); filter.setIncludeClientInfo(true); filter.setIncludeQueryString(true); filter.setIncludePayload(true); filter.setMaxPayloadLength(10000); // 根据需求调整 payload 打印长度 filter.setIncludeHeaders(false); return filter; }
二、解决自定义OidcUserService未触发的问题
1. 检查Keycloak客户端基础配置
- 确保Keycloak客户端的Access Type设置为
confidential(后端应用场景),并在Spring配置中补充客户端密钥:
spring: security: oauth2: client: registration: keycloak: client-id: myclientid client-secret: your-keycloak-client-secret # 从Keycloak控制台获取
- 确认Keycloak客户端已启用User Info端点(控制台客户端设置中
User Info Enabled设为On)。
2. 强制触发User Info端点调用
若ID Token已包含所有必要信息,Spring Security可能跳过User Info请求,需显式关闭useIdTokenForUserInfo:
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .anyRequest().authenticated() .and() .oauth2Login() .userInfoEndpoint() .oidcUserService(oidcUserService()); }
或通过配置文件设置:
spring.security.oauth2.client.provider.keycloak.use-id-token-for-user-info=false
3. 确保自定义Bean优先级
添加@Primary注解,避免自定义OidcUserService被自动配置的Bean覆盖:
@Bean @Primary public OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() { final OidcUserService delegate = new OidcUserService(); return (userRequest) -> { OidcUser oidcUser = delegate.loadUser(userRequest); log.debug("User "+oidcUser.toString()); log.debug("UserInfo "+oidcUser.getUserInfo().toString()); log.debug("UserClaims "+oidcUser.getClaims().toString()); log.debug("UserToken "+oidcUser.getIdToken().toString()); final Map<String, Object> claims = oidcUser.getClaims(); final JSONArray groups = (JSONArray) claims.get("org_access"); final Set<GrantedAuthority> mappedAuthorities = groups.stream() .map(role -> new SimpleGrantedAuthority(""+role)) .collect(Collectors.toSet()); return new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo()); }; }
4. 流程验证
清除浏览器缓存或使用隐身窗口重新发起登录,确保走完整的授权码流程;同时检查Keycloak日志,确认是否收到User Info请求。
内容的提问来源于stack exchange,提问作者Eljah
相关产品推荐
相关产品推荐

