You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 14:32:20