Spring Security注册密码为空问题求助及完整代码排查
Spring Security注册后密码为空导致登录失败问题
我在基于Spring Security的登录注册程序中遇到一个严重bug:用户完成注册并提交信息后,所有数据本该存储到PostgreSQL数据库中,随后用户可登录个人主页。但实际注册提交后,密码字段为空,其他字段均正常填充,导致登录时触发我预设的「Invalid email or password」错误。我推测问题可能与密码编码有关,但不知如何修复。
安全配置
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf() .disable() .authorizeRequests() .antMatchers("/").permitAll() .antMatchers("/css/**").permitAll() .antMatchers("/js/**").permitAll() .antMatchers("/img/**").permitAll() .antMatchers("/registration/**").permitAll() .antMatchers("/").permitAll() .anyRequest() .authenticated() .and() .formLogin() .loginPage("/login").permitAll() .loginProcessingUrl("/login") .defaultSuccessUrl("/profile") .and() .logout() .logoutUrl("/logout") .logoutSuccessUrl("/") .and() .httpBasic(); return http.build(); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
授权控制器
@AllArgsConstructor @Controller public class AuthController { private final EmployeeService employeeService; @GetMapping("/") public String getHomePage() { return "home"; } @GetMapping("/login") public String getLoginPage() { return "login"; } @GetMapping("/profile") public String getSuccessPage() { return "profile"; } @GetMapping("registration") public String getRegisterPage(Model model) { EmployeeDto employee = new EmployeeDto(); model.addAttribute("user", employee); return "registration"; } @PostMapping("/registration/save") public String postRegisterPage(@Valid @ModelAttribute("user") EmployeeDto employee, BindingResult result, Model model){ Optional<Employee> existing = employeeService.findByEmail(employee.getEmail()); if (existing != null) { result.rejectValue("email", null, "There is already an account registered with that email"); } if (result.hasErrors()) { model.addAttribute("user", employee); return "registration"; } employeeService.saveAndFlush(employee); return "redirect:/registration?success"; } }
Employee DTO
@Getter @Setter @NoArgsConstructor @AllArgsConstructor public class EmployeeDto { private Long id; @NotEmpty private String firstName; @NotEmpty private String lastName; @NotEmpty(message = "Email should not be empty") @Email private String email; @NotEmpty(message = "Password should not be empty") private String password; @NotEmpty(message = "Department should not be empty") private String department; @NotEmpty(message = "Birth date should not be empty") private String birthDate; @NotEmpty(message = "Phone number should not be empty") private String phoneNumber; }
实体类
@Getter @Setter @ToString @Entity @Table(name = "employees") public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "first_name", nullable = false) private String firstName; @Column(name = "last_name", nullable = false) private String lastName; @Column(name = "department", nullable = false) private String department; @Column(name = "birth_date", nullable = false) private String birthDate; @Column(name = "phone_number", nullable = false) private String phoneNumber; @Column(name = "email", nullable = false, unique = true) private String email; @Column(name = "password", nullable = false) private String password; @ManyToMany(fetch = FetchType.EAGER, cascade=CascadeType.ALL) @JoinTable( name="employees_roles", joinColumns={@JoinColumn(name="EMPLOYEE_ID", referencedColumnName="ID")}, inverseJoinColumns={@JoinColumn(name="ROLE_ID", referencedColumnName="ID")}) private List<Role> roles = new ArrayList<>(); } @Setter @Getter @NoArgsConstructor @AllArgsConstructor @Entity @Table(name="roles") public class Role { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable=false, unique=true) private String name; @ManyToMany(mappedBy="roles") private List<Employee> employee; }
Employee与Role仓库
@Repository public interface EmployeeRepository extends JpaRepository<Employee, Long>{ Optional<Employee> findByEmail(String email); } @Repository public interface RoleRepository extends JpaRepository<Role, Long> { Role findByName(String name); }
Employee服务接口
public interface EmployeeService { void saveAndFlush(EmployeeDto employeeDto); Optional<Employee> findByEmail(String email); List<EmployeeDto> findAll(); }
Employee服务实现类
@Service public class EmployeeServiceImpl implements EmployeeService { @Autowired private EmployeeRepository employeeRepository; private RoleRepository roleRepository; private PasswordEncoder passwordEncoder; @Override public void saveAndFlush(EmployeeDto employeeDto) { Employee employee = new Employee(); employee.setEmail(employeeDto.getEmail()); employee.setPassword(passwordEncoder.encode(employeeDto.getPassword())); Role role = roleRepository.findByName("ROLE_ADMIN"); if(role == null){ role = checkRoleExist(); } employee.setRoles(Arrays.asList(role)); employeeRepository.save(employee); } @Override public Optional<Employee> findByEmail(String email) { return employeeRepository.findByEmail(email); } @Override public List<EmployeeDto> findAll() { List<Employee> employees = employeeRepository.findAll(); return employees.stream().map((employee) -> convertEntityToDto(employee)) .collect(Collectors.toList()); } private EmployeeDto convertEntityToDto(Employee employee){ EmployeeDto employeeDto = new EmployeeDto(); employeeDto.setEmail(employee.getEmail()); return employeeDto; } private Role checkRoleExist() { Role role = new Role(); role.setName("ROLE_ADMIN"); return roleRepository.save(role); } }
Employee详情服务实现类
@Service public class EmployeeDetailsServiceImpl implements UserDetailsService { private EmployeeRepository employeeRepository; public EmployeeDetailsServiceImpl(EmployeeRepository employeeRepository) { this.employeeRepository = employeeRepository; } @SuppressWarnings("unchecked") @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { Employee employee = employeeRepository.findByEmail(email).orElseThrow(() -> new UsernameNotFoundException("User doesn't exists")); return new org.springframework.security.core.userdetails.User( employee.getEmail(), employee.getPassword(), (Collection<? extends GrantedAuthority>) Set.of(employee.getRoles()) ); } }
HTML登录表单
<body> <div class="container"> <div class="forms"> <div class="form-content"> <div class="login-form"> <div class="title">Вхід</div> <div th:if="${param.error}"> <div class="alert alert-danger">Invalid Email or Password</div> </div> <form method="post" role="form" th:action="@{/login}"> <div class="input-boxes"> <div class="input-box"> <i class="fas fa-envelope"></i> <input type="text" placeholder="Введіть пошту" id="email" name="email" required/> </div> <div class="input-box"> <i class="fas fa-lock"></i> <input type="password" placeholder="Введіть пароль" id="password" name="password" required/> </div> <div class="button input-box"> <input type="submit" value="Вхід"> </div> <div class="text sign-up-text"> <label> <a href="@{/registration}">Зареєструватися</a> </label> </div> </div> </form> </div> </div> </div> </div> </body> </html>
HTML注册表单
<body> <div class="container"> <div class="forms"> <div class="form-content"> <div class="login-form"> <div class="title">Реєстрація</div> <div th:if="${param.success}"> <div class="alert alert info">You've successfully registered to our app!</div> </div> <form method="post" role="form" th:action="@{/registration/save}" th:object="${user}"> <div class="input-boxes"> <div class="input-box"> <i class="fas fa-pencil-alt"></i> <input type="text" placeholder="Введіть ім'я" id="firstName" name="firstName" th:field="*{firstName}"/> <p th:errors="*{firstName}" class="text-danger" th:if="${#fields.hasErrors('firstName')}"> </p> </div> <div class="input-box"> <i class="fas fa-pencil-alt"></i> <input type="text" placeholder="Введіть прізвище" id="lastName" name="lastName" th:field="*{lastName}"/> <p th:errors="*{lastName}" class="text-danger" th:if="${#fields.hasErrors('lastName')}"> </p> </div> <div class="input-box"> <i class="fas fa-envelope"></i> <input type="text" placeholder="Введіть пошту" id="email" name="email" th:field="*{email}"/> <!-- <p th:errors="*{email}" class="text-danger" th:if="${#fields.hasErrors('email')}"> </p> --> </div> <div class="input-box"> <i class="fas fa-lock"></i> <input type="password" placeholder="Введіть пароль" id="password" name="password" th:field="*{password}"/> <p th:errors="*{password}" class="text-danger" th:if="${#fields.hasErrors('password')}"> </p> </div> <div class="input-box"> <i class="fa fa-calendar"></i> <input type="text" placeholder="Введіть дату народження" id="birthDate" name="birthDate" th:field="*{birthDate}"/> <p th:errors="*{birthDate}" class="text-danger" th:if="${#fields.hasErrors('birthDate')}"> </p> </div> <div class="input-box"> <i class=" fas fa-pencil-alt"></i> <input type="text" placeholder="Введіть підрозділ" id="department" name="department" th:field="*{department}"/> <p th:errors="*{department}" class="text-danger" th:if="${#fields.hasErrors('department')}"> </p> </div> <div class="input-box"> <i class=" fas fa-pencil-alt"></i> <input type="text" placeholder="Введіть номер телефону" id="phoneNumber" name="phoneNumber" th:field="*{phoneNumber}"/> <p th:errors="*{phoneNumber}" class="text-danger" th:if="${#fields.hasErrors('phoneNumber')}"> </p> </div> <div class="button input-box"> <input type="submit" value="Зареєструватися"> </div> <div class="text sign-in-text"><label><a th:href="@{/login}">Увійти</a></label></div> </div> </form> </div> </div> </div> </div> </body> </html>
内容的提问来源于stack exchange,提问作者Artostapyshyn
相关产品推荐
相关产品推荐

