从Spring Security OAuth迁移至Core 6.1.0遇principalName不能为空错误
1. 确保认证上下文存在有效Principal
这个错误的核心是调用loadAuthorizedClient时,当前SecurityContext中的Authentication对象为空或其principalName为空。
- 集成测试场景:用
@WithMockUser注解模拟认证用户,确保测试上下文有有效主体:
@SpringBootTest @AutoConfigureMockMvc public class YourApiTest { @Test @WithMockUser(username = "test-user", authorities = {"ROLE_USER"}) public void testApiCall() throws Exception { // 测试逻辑 } }
如果是手动构造请求的测试,也可以手动设置SecurityContext:
SecurityContextHolder.getContext().setAuthentication( new UsernamePasswordAuthenticationToken("test-user", null, Collections.emptyList()) );
- API调用场景:检查你的认证过滤器是否正确将认证信息存入
SecurityContext。比如使用OAuth2登录时,确保OAuth2LoginAuthenticationFilter已正确配置在SecurityFilterChain中:
@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth.anyRequest().authenticated()) .oauth2Login(withDefaults()); // 确保OAuth2登录配置生效 return http.build(); }
2. 自定义AuthorizedClientService绕过校验
如果你的场景不需要严格校验principalName(比如某些无用户的后台服务调用),可以自定义AuthorizedClientService,继承默认的InMemoryOAuth2AuthorizedClientService并重写校验逻辑:
@Bean public OAuth2AuthorizedClientService authorizedClientService( ClientRegistrationRepository clientRegistrationRepository) { return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository) { @Override public OAuth2AuthorizedClient loadAuthorizedClient(String clientRegistrationId, String principalName) { // 处理空principalName的情况,比如默认使用一个固定值,或者直接跳过校验 String safePrincipalName = StringUtils.hasText(principalName) ? principalName : "default-principal"; return super.loadAuthorizedClient(clientRegistrationId, safePrincipalName); } }; }
注意:这种方式仅适用于非用户绑定的客户端场景,若需要用户级的授权客户端管理,不建议这么做。
3. 检查是否误用了AuthorizedClientService
如果你的场景不需要使用用户绑定的授权客户端(比如客户端模式的OAuth2调用),应该使用OAuth2AuthorizedClientManager的客户端模式配置,而不是依赖AuthorizedClientService:
@Bean public OAuth2AuthorizedClientManager authorizedClientManager( ClientRegistrationRepository clientRegistrationRepository, OAuth2AuthorizedClientService authorizedClientService) { OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder() .clientCredentials() .build(); DefaultOAuth2AuthorizedClientManager authorizedClientManager = new DefaultOAuth2AuthorizedClientManager( clientRegistrationRepository, authorizedClientService); authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider); // 客户端模式下,设置默认的principalName生成器 authorizedClientManager.setContextAttributesMapper(contextAttributesMapper()); return authorizedClientManager; } private Function<OAuth2AuthorizeRequest, Map<String, Object>> contextAttributesMapper() { return authorizeRequest -> { Map<String, Object> contextAttributes = new HashMap<>(); // 客户端模式下,principalName可以设为客户端ID或固定值 contextAttributes.put(OAuth2AuthorizationContext.PRINCIPAL_NAME_ATTRIBUTE_NAME, authorizeRequest.getClientRegistration().getClientId()); return contextAttributes; }; }
内容的提问来源于stack exchange,提问作者Cole Gvozdas
相关产品推荐
相关产品推荐

