使用Spring Security注册时出现rawPassword cannot be null异常排查
问题排查:Spring Security注册时rawPassword cannot be null异常
问题场景
使用Spring Security的SecurityFilterChain配置安全规则,已定义BCryptPasswordEncoder Bean,但用户注册接口调用时抛出rawPassword cannot be null异常,相关代码如下:
SpringSecurity配置类
@Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public class SpringSecurity { private final RecipesUserDetailsService userDetailsService; @Autowired public SpringSecurity(RecipesUserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public DaoAuthenticationProvider authenticationProvider() { DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(); authProvider.setUserDetailsService(userDetailsService); authProvider.setPasswordEncoder(passwordEncoder()); return authProvider; } @Bean SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.httpBasic() .and() .authorizeRequests() .antMatchers("/api/register").anonymous() .antMatchers("/actuator/shutdown").anonymous() .antMatchers("/h2-console/**").anonymous() .anyRequest().authenticated() .and() .csrf().disable() .headers().frameOptions().disable(); return http.build(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(authenticationProvider()); } }
RecipesUserDetailsService
@Service @AllArgsConstructor public class RecipesUserDetailsService implements UserDetailsService { private final UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findById(username) .orElseThrow(() -> new UsernameNotFoundException("User not found")); return new RecipeUserDetails(user); } }
错误日志
2023-04-21 04:41:09.574 ERROR 404954 --- [nio-8822-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: rawPassword cannot be null] with root cause java.lang.IllegalArgumentException: rawPassword cannot be null at org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder.encode(BCryptPasswordEncoder.java:107) ~[spring-security-crypto-5.5.3.jar:5.5.3] at recipes.service.UserService.add(UserService.java:26) ~[classes/:na] at recipes.controller.RegistrationController.register(RegistrationController.java:29) ~[classes/:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na] at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
注册Controller
@ResponseStatus(HttpStatus.OK) public void register(@JsonView(UserJsonView.RegistrationView.class) @Valid @RequestBody User user){ userService.add(user); }
UserService
@Service public class UserService { private final UserRepository userRepository; private final PasswordEncoder passwordEncoder; @Autowired public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) { this.userRepository = userRepository; this.passwordEncoder = passwordEncoder; } public void add(User user) { if (userRepository.existsById(user.getEmail())) { throw new KeyAlreadyExistsException(); } String encodedPassword = passwordEncoder.encode(user.getPassword()); user.setPassword(encodedPassword); userRepository.save(user); } public void addTest(User user) { userRepository.save(user); } }
User实体类
@Entity @Table(name = "USERS") @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class User { @Id @NotBlank @Email(regexp = "^(?=.{1,64}@)[A-Za-z0-9\\+_-]+(\\.[A-Za-z0-9\\+_-]+)*@" + "[^-][A-Za-z0-9\\+-]+(\\.[A-Za-z0-9\\+-]+)*(\\.[A-Za-z]{2,})$") @JsonView(UserJsonView.RegistrationView.class) private String email; @Size(min = 8) private String password; @OneToMany(mappedBy = "user",cascade = CascadeType.ALL) private Set<Recipe> recipe; }
问题根源
注册接口使用了@JsonView(UserJsonView.RegistrationView.class)注解,但User实体类的password字段未添加该注解,导致请求JSON中的password字段无法被反序列化到User对象中,调用passwordEncoder.encode(user.getPassword())时传入null,触发BCryptPasswordEncoder的非空校验异常。
修复方案
修改User实体类的password字段,添加对应的@JsonView注解:
@Size(min = 8) @JsonView(UserJsonView.RegistrationView.class) // 新增此注解,确保password字段被反序列化 private String password;
额外验证
- 确保注册请求的JSON包含
password字段,且长度至少为8位 - 确认
@Valid注解生效:若请求缺少password或不符合长度要求,应返回400 Bad Request,避免进入service层执行加密逻辑
内容的提问来源于stack exchange,提问作者lulzeR
相关产品推荐
相关产品推荐

