Spring OAuth2密码流资源服务器报错:未找到PreAuthenticatedAuthenticationProvider
解决Spring OAuth2资源服务器ProviderNotFoundException问题
嘿,这个问题我之前帮不少开发者踩过坑,咱们一步步来排查你可能的配置疏漏:
1. 先检查依赖是否正确且版本匹配
这个错误常出现在依赖缺失或者版本冲突的情况:
- 如果你的Spring Boot版本在2.4+,确保引入了
spring-security-oauth2-resource-server和spring-security-oauth2-jose(处理JWT所需)。比如Maven依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-resource-server</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-oauth2-jose</artifactId> </dependency>
- 避免同时引入旧版的
spring-security-oauth2-autoconfigure或spring-security-oauth2,它们和新版资源服务器依赖会产生冲突,导致Spring Security无法正确加载认证Provider。
2. 资源服务器配置类是否正确配置了令牌解析逻辑
这是最常见的疏漏点,分两种情况看:
情况A:使用JWT令牌(推荐方式)
如果授权服务器发放的是JWT,你需要告诉资源服务器如何验证JWT的合法性:
- 新版本Spring Security(5.7+):推荐用
SecurityFilterChain替代过时的@EnableResourceServer,示例配置:
@Configuration @EnableWebSecurity public class ResourceServerConfig { // 对称加密用signing-key,非对称用jwk-set-uri,二选一 @Value("${spring.security.oauth2.resourceserver.jwt.signing-key}") private String signingKey; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .anyRequest().authenticated() ) .oauth2ResourceServer(oauth2 -> oauth2 .jwt(jwt -> jwt .signingKey(signingKey) // 和授权服务器的签名密钥一致 .jwtAuthenticationConverter(customJwtConverter()) // 可选:自定义权限转换 ) ); return http.build(); } // 自定义JWT权限转换(可选,根据你的JWT claim结构调整) private JwtAuthenticationConverter customJwtConverter() { JwtGrantedAuthoritiesConverter authoritiesConverter = new JwtGrantedAuthoritiesConverter(); authoritiesConverter.setAuthorityPrefix("ROLE_"); authoritiesConverter.setAuthoritiesClaimName("roles"); // 对应JWT里的权限字段名 JwtAuthenticationConverter converter = new JwtAuthenticationConverter(); converter.setJwtGrantedAuthoritiesConverter(authoritiesConverter); return converter; } }
- 旧版本Spring Security:用
@EnableResourceServer配合JwtTokenStore:
@EnableResourceServer @Configuration public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().authenticated(); } @Bean public TokenStore tokenStore() { return new JwtTokenStore(jwtAccessTokenConverter()); } @Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey("your-shared-secret"); // 和授权服务器一致 return converter; } }
情况B:使用非JWT令牌(比如普通OAuth2令牌)
如果授权服务器用的是内存/Redis存储令牌,资源服务器需要和授权服务器共享TokenStore,示例:
@EnableResourceServer @Configuration public class ResourceServerConfig extends ResourceServerConfigurerAdapter { // 注入和授权服务器相同的TokenStore(比如RedisTokenStore) @Autowired private TokenStore tokenStore; @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.tokenStore(tokenStore); // 关键:指定令牌存储方式 } @Override public void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().authenticated(); } }
3. 确认授权服务器和资源服务器的令牌配置一致
- 如果用对称加密,两边的
signing-key必须完全相同; - 如果用非对称加密,资源服务器要配置正确的
jwk-set-uri(指向授权服务器的JWK端点); - 确保授权服务器发放的令牌格式和资源服务器期望的一致(JWT vs 普通令牌)。
4. 排查配置文件是否正确
比如application.yml里的资源服务器配置:
spring: security: oauth2: resourceserver: jwt: # 对称加密用这个 signing-key: "your-shared-secret-key" # 非对称加密用这个(替换成你的授权服务器JWK地址) # jwk-set-uri: http://localhost:8080/oauth2/jwks
如果以上步骤都检查过,应该就能解决ProviderNotFoundException的问题了——本质上就是Spring Security找不到能处理令牌的认证Provider,要么是依赖没配对,要么是令牌解析逻辑没配置。
内容的提问来源于stack exchange,提问作者Irios
相关产品推荐
相关产品推荐

