能否从UserDetailsService Bean中获取PasswordEncoder Bean?
关于WebSecurityConfigurerAdapter中PasswordEncoder与UserDetailsService的关联问题
核心结论
不能从UserDetailsService实例中提取通过AuthenticationManagerBuilder设置的PasswordEncoder,如果UserDetailsService的业务逻辑里需要用到PasswordEncoder(比如加密新用户密码),必须单独注入这个Bean,没法依赖Security配置里的设置。
具体原因
- 绑定关系是单向的:你在
configure(AuthenticationManagerBuilder auth)里的配置,只是把PasswordEncoder关联到Spring Security的身份验证流程中——用来校验用户输入的明文密码和UserDetails返回的加密密码是否匹配。这个绑定是Security框架内部的逻辑,并不会把PasswordEncoder注入到你的UserDetailsService实例里,两者之间没有属性传递的动作。 - 代码层面无关联:看你贴的这段代码:
这里的@Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); }passwordEncoder()是给AuthenticationManagerBuilder的配置链添加编码器,和传入的userDetailsService实例没有任何赋值操作。你的UserDetailsService实现类如果没有显式声明依赖PasswordEncoder,那对应的属性就是null。 - 场景完全不同:Security配置里的PasswordEncoder是用于登录校验阶段,而UserDetailsService需要PasswordEncoder的场景一般是用户注册、密码修改这类业务操作,这是两个独立的逻辑,Security不会把校验用的编码器自动同步到业务逻辑里。
实际示例
比如你的UserDetailsService实现类包含用户创建逻辑,就必须显式注入PasswordEncoder:
@Service public class CustomUserDetailsService implements UserDetailsService { private final PasswordEncoder passwordEncoder; // 必须通过构造器注入PasswordEncoder public CustomUserDetailsService(PasswordEncoder passwordEncoder) { this.passwordEncoder = passwordEncoder; } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 从数据库加载用户信息的逻辑 return new User(user.getUsername(), user.getEncodedPassword(), user.getAuthorities()); } // 业务方法:创建新用户,需要加密密码 public void createNewUser(UserForm userForm) { String encodedPwd = passwordEncoder.encode(userForm.getPassword()); // 保存加密后的密码到数据库 } }
内容的提问来源于stack exchange,提问作者haoz
相关产品推荐
相关产品推荐

