setEraseCredentialsAfterAuthentication(false)不生效问题求助
问题排查:自定义AuthenticationManager不生效,Feign拦截器中凭证为null
可能的原因及排查步骤
1. 系统实际使用的不是你定义的AuthenticationManager Bean
Spring Security在部分场景下会自动创建默认的AuthenticationManager实例,可能覆盖你自定义的Bean。
- 排查与修复:
- 给你的
authenticationManager()方法添加@Primary注解,确保它被优先注入:@Bean @Primary AuthenticationManager authenticationManager() { log.debug("ANDY: In authenticationManager...."); ProviderManager providerManager = new ProviderManager(authenticationProvider); if (providerManager.isEraseCredentialsAfterAuthentication()) { log.debug("ANDY: Provider set to erase creds, changing to NOT do this"); providerManager.setEraseCredentialsAfterAuthentication(false); } return providerManager; } - 调试时,在Feign拦截器中打印Authentication对象的类名,确认是否是你创建的
ProviderManager处理后的实例。
- 给你的
2. 自定义AuthenticationProvider提前清除了凭证
你的自定义AuthenticationProvider在authenticate方法返回Authentication对象时,可能已将credentials设为null,导致后续即使ProviderManager不清除,也拿不到值。
- 排查与修复:
- 检查AuthenticationProvider的实现,确保返回的Authentication对象保留原始凭证:
@Override public Authentication authenticate(Authentication auth) throws AuthenticationException { String username = auth.getName(); String password = auth.getCredentials().toString(); // 你的认证逻辑... // 返回时传入原始credentials,不要设为null return new UsernamePasswordAuthenticationToken(username, password, authorities); } - 在AuthenticationProvider的
authenticate方法末尾,打印返回对象的credentials,确认此时值存在。
- 检查AuthenticationProvider的实现,确保返回的Authentication对象保留原始凭证:
3. 认证后凭证被其他Security组件清除
即使ProviderManager设置了eraseCredentialsAfterAuthentication=false,后续的过滤器链或Session管理组件仍可能修改Authentication对象,清除凭证。
- 排查方式:
- 在认证完成后(比如AuthenticationProvider返回后、Controller方法入口),立即打印
SecurityContextHolder.getContext().getAuthentication().getCredentials(),确认此时有值。 - 在Feign拦截器中同样打印该值,对比两个位置的结果,判断凭证是在哪一步被清空的。
- 在认证完成后(比如AuthenticationProvider返回后、Controller方法入口),立即打印
4. Feign拦截器获取的Authentication不合法
如果Feign调用是异步执行的,SecurityContext可能无法正确传递,导致拦截器拿到匿名用户的Authentication或null。
- 排查与修复:
- 确认拦截器中获取Authentication的代码逻辑正确:
@Override public void apply(RequestTemplate template) { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && !(auth instanceof AnonymousAuthenticationToken) && auth.isAuthenticated()) { String password = auth.getCredentials().toString(); // 你的处理逻辑 } } - 如果是异步Feign调用,需配置SecurityContext传递,比如用
DelegatingSecurityContextExecutor包装异步任务,或在Feign配置中开启上下文传递。
- 确认拦截器中获取Authentication的代码逻辑正确:
内容的提问来源于stack exchange,提问作者Tallen67
相关产品推荐
相关产品推荐

