Micronaut框架中PasswordEncoder实例化失败问题求助
问题
作为Micronaut框架新手,在实现用户注册功能时,将AuthenticationProvider逻辑抽离到AuthService后,发起注册POST请求时出现Bean实例化错误,核心异常为java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory,根源是Spring Security的BCryptPasswordEncoder依赖的日志类缺失。
相关代码如下:
UserAuthProvider
@Singleton public class UserAuthProvider implements AuthenticationProvider { private final AuthService authService; public UserAuthProvider(AuthService authService) { this.authService = authService; } @Override public Publisher<AuthenticationResponse> authenticate(HttpRequest<?> httpRequest, AuthenticationRequest<?, ?> authenticationRequest) { return Flux.create(emitter -> { var username = authenticationRequest.getIdentity().toString(); var password = authenticationRequest.getSecret().toString(); var user = this.authService.getValidatedUser(username, password); if (user != null) { emitter.next(AuthenticationResponse.success(username, List.of(user.roleId().toString()))); emitter.complete(); } else { emitter.error(AuthenticationResponse.exception()); } }, FluxSink.OverflowStrategy.ERROR); } }
AuthService
@Singleton public class AuthService { private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; private final RoleRepository roleRepository; public AuthService(UserRepository userRepository, PasswordEncoder passwordEncoder, RoleRepository roleRepository) { this.userRepository = userRepository; this.passwordEncoder = passwordEncoder; this.roleRepository = roleRepository; } public void register(RegistrationRequest registrationRequest) { var user = this.userRepository.findByEmailEmail(registrationRequest.email()); if (user.isPresent()) { throw new EntityAlreadyExistsException(String.format(EMAIL_ALREADY_EXISTS,registrationRequest.email())); } var role = this.roleRepository.findByName(RoleEnum.ROLE_PARENT) .orElseThrow(() -> new EntityNotFoundException(ENTITY_NOT_FOUND)); var newUser = new ApplicationUser( new Email(registrationRequest.email()), this.passwordEncoder.encode(registrationRequest.password()), registrationRequest.firstName(), registrationRequest.middleName(), registrationRequest.lastName(), new MobilePhone(registrationRequest.phoneNumber()), role ); var patient = new Parent(); newUser.setParent(patient); this.userRepository.save(newUser); } public UserDto getValidatedUser(String username, String password) { if (this.validateCredentials(username, password)) { return this.findByEmail(username); } return null; } private boolean validateCredentials(String username, String password) { var user = this.userRepository.findByEmailEmail(username) .orElseThrow(() -> new EntityNotFoundException(ENTITY_NOT_FOUND)); return this.passwordEncoder.matches(password, user.getPassword()); } public UserDto findByEmail(String email) { return this.userRepository.findByEmailEmail(email) .map(u -> new UserDto( u.getId(), u.getFirstName(), u.getLastName(), u.getEmail().getEmail(), u.getRole().getId())) .orElseThrow(() -> new EntityNotFoundException(ENTITY_NOT_FOUND)); } }
AuthPasswordEncoderService
package server.infrastructure.config.encoding; import jakarta.inject.Singleton; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @Singleton public class AuthPasswordEncoderService implements PasswordEncoder { PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); @Override public String encode(CharSequence rawPassword) { return this.passwordEncoder.encode(rawPassword); } @Override public boolean matches(CharSequence rawPassword, String encodedPassword) { return this.passwordEncoder.matches(rawPassword, encodedPassword); } }
错误核心堆栈:
Caused by: java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory at org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder.<init>(BCryptPasswordEncoder.java:40) at server.infrastructure.config.encoding.AuthPasswordEncoderService.<init>(AuthPasswordEncoderService.java:9) ... Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory
解决方案
方案一:补充缺失的Commons Logging依赖
Spring Security的BCryptPasswordEncoder依赖Apache Commons Logging组件,需在构建文件中添加该依赖:
Gradle(Groovy)
implementation 'commons-logging:commons-logging:1.2'
Maven
<dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency>
方案二:改用Micronaut原生PasswordEncoder(推荐)
Micronaut Security自带BCrypt密码编码实现,无需依赖Spring Security组件,更适配框架生态:
- 确保引入Micronaut Security Password依赖:
Gradle(Groovy)
implementation("io.micronaut.security:micronaut-security-password")
- 修改
AuthPasswordEncoderService代码:
package server.infrastructure.config.encoding; import jakarta.inject.Singleton; import io.micronaut.security.authentication.password.PasswordEncoder; import io.micronaut.security.password.bcrypt.BCryptPasswordEncoder; import io.micronaut.security.password.PasswordEncoderConfiguration; @Singleton public class AuthPasswordEncoderService implements PasswordEncoder { private final PasswordEncoder passwordEncoder; public AuthPasswordEncoderService(PasswordEncoderConfiguration configuration) { this.passwordEncoder = new BCryptPasswordEncoder(configuration); } @Override public String encode(CharSequence rawPassword) { return passwordEncoder.encode(rawPassword); } @Override public boolean matches(CharSequence rawPassword, String encodedPassword) { return passwordEncoder.matches(rawPassword, encodedPassword); } }
内容的提问来源于stack exchange,提问作者AchoVasilev
相关产品推荐
相关产品推荐

