增加忘记密码功能

pull/2/head
陈映江 5 months ago
parent 6bdec54a93
commit 7884e56895

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

@ -1,8 +1,8 @@
[ {
"username" : "小鱼",
"email" : "1280556515@qq.com",
"passwordHash" : "$2a$12$J6oCgotwddD.tOspkOnMlOBcB9C7RcMNmR0MvaCuAutnIneXSrHm6",
"passwordHash" : "$2a$12$0.CsIN83oxG1vbZe6vNVte3JaxvX2JU2j0hyprng6meq9/N4e732m",
"registrationDate" : [ 2025, 10, 8, 21, 0, 37, 863490500 ],
"verificationCode" : "658919",
"verificationCode" : "963213",
"verified" : true
} ]

@ -147,6 +147,48 @@ public class UserService {
return true;
}
public boolean setPasswordResetCode(String email, String verificationCode) {
User user = users.get(email);
if (user == null) {
return false; // 用户不存在
}
user.setVerificationCode(verificationCode);
verificationCodeTimestamps.put(email, LocalDateTime.now());
saveUsers();
return true;
}
public boolean resetPasswordWithCode(String email, String verificationCode, String newPassword) {
User user = users.get(email);
if (user == null) {
return false;
}
// 验证验证码
if (!user.getVerificationCode().equals(verificationCode)) {
return false;
}
// 检查验证码是否过期
LocalDateTime codeTime = verificationCodeTimestamps.get(email);
if (codeTime == null || codeTime.plusMinutes(VERIFICATION_CODE_EXPIRY_MINUTES).isBefore(LocalDateTime.now())) {
return false;
}
// 验证新密码格式
if (!validatePassword(newPassword)) {
return false;
}
// 更新密码
String newPasswordHash = BCrypt.withDefaults().hashToString(12, newPassword.toCharArray());
user.setPasswordHash(newPasswordHash);
verificationCodeTimestamps.remove(email); // 清除验证码
saveUsers();
return true;
}
public boolean validatePassword(String password) {
if (password.length() < 6 || password.length() > 10) {
return false;
@ -169,6 +211,11 @@ public class UserService {
return users.containsKey(email);
}
public boolean isUserExistsAndVerified(String email) {
User user = users.get(email);
return user != null && user.isVerified();
}
public boolean isValidEmail(String email) {
return email.matches("^[A-Za-z0-9+_.-]+@(.+)$");
}

@ -0,0 +1,226 @@
package mathlearning.ui;
import at.favre.lib.crypto.bcrypt.BCrypt;
import mathlearning.model.User;
import mathlearning.service.EmailService;
import mathlearning.service.UserService;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ChangeCodeFrame extends JFrame {
private UserService userService;
private EmailService emailService;
private LoginFrame loginFrame;
private JTextField emailField;
private JButton sendCodeButton;
private JTextField codeField;
private JPasswordField passwordField;
private JPasswordField confirmPasswordField;
private JButton registerButton;
private JButton backButton;
private String verificationCode;
public ChangeCodeFrame(UserService userService, LoginFrame loginFrame) {
this.userService = userService;
this.loginFrame = loginFrame;
// 配置邮箱服务(需要替换为真实的邮箱配置)
this.emailService = new EmailService(
"smtp.qq.com",
"587",
"2793415226@qq.com", // 替换为你的QQ邮箱
"rmiomlakglpjddhb", // 替换为你的授权码
true
);
initializeUI();
}
private void initializeUI() {
setTitle("数学学习软件 - 忘记密码");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(450, 400);
setLocationRelativeTo(null);
setResizable(false);
// 主面板
JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
// 标题
JLabel titleLabel = new JLabel("重置密码", JLabel.CENTER);
titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 24));
mainPanel.add(titleLabel, BorderLayout.NORTH);
//表单面板
JPanel formPanel = new JPanel(new GridLayout(5, 2, 10, 10));
JLabel emailLabel = new JLabel("邮箱:");
emailLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
emailField = new JTextField();
JLabel codeLabel = new JLabel("验证码:");
codeLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
JPanel codePanel = new JPanel(new BorderLayout());
codeField = new JTextField();
sendCodeButton = new JButton("发送验证码");
sendCodeButton.addActionListener(new SendCodeListener());
codePanel.add(codeField, BorderLayout.CENTER);
codePanel.add(sendCodeButton, BorderLayout.EAST);
JLabel passwordLabel = new JLabel("新密码:");
passwordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
passwordField = new JPasswordField();
JLabel confirmPasswordLabel = new JLabel("确认密码:");
confirmPasswordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
confirmPasswordField = new JPasswordField();
formPanel.add(emailLabel);
formPanel.add(emailField);
formPanel.add(codeLabel);
formPanel.add(codePanel);
formPanel.add(passwordLabel);
formPanel.add(passwordField);
formPanel.add(confirmPasswordLabel);
formPanel.add(confirmPasswordField);
mainPanel.add(formPanel, BorderLayout.CENTER);
// 按钮面板
JPanel buttonPanel = new JPanel(new FlowLayout());
registerButton = new JButton("更改密码");
registerButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
registerButton.addActionListener(new ChangeCodeFrame.ChangeCodeButtonListener());
backButton = new JButton("返回登录");
backButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
backButton.addActionListener(e -> goBackToLogin());
buttonPanel.add(registerButton);
buttonPanel.add(backButton);
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
add(mainPanel);
}
private class SendCodeListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
String email = emailField.getText().trim();
if (email.isEmpty()) {
JOptionPane.showMessageDialog(ChangeCodeFrame.this,
"请输入邮箱地址", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
if (!userService.isValidEmail(email)) {
JOptionPane.showMessageDialog(ChangeCodeFrame.this,
"邮箱格式不正确", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
// 检查用户是否存在且已验证
if (!userService.isUserExistsAndVerified(email)) {
JOptionPane.showMessageDialog(ChangeCodeFrame.this,
"该邮箱未注册或未验证", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
// 生成6位验证码
verificationCode = String.valueOf((int)((Math.random() * 9 + 1) * 100000));
// 发送验证码邮件
boolean sent = emailService.sendVerificationCode(email, verificationCode);
if (sent) {
// 在服务中保存验证码
boolean codeSaved = userService.setPasswordResetCode(email, verificationCode);
if (codeSaved) {
JOptionPane.showMessageDialog(ChangeCodeFrame.this,
"验证码已发送到您的邮箱,请查收", "成功", JOptionPane.INFORMATION_MESSAGE);
// 禁用发送按钮60秒
sendCodeButton.setEnabled(false);
new Thread(() -> {
try {
for (int i = 60; i > 0; i--) {
final int current = i;
SwingUtilities.invokeLater(() ->
sendCodeButton.setText(current + "秒后重发"));
Thread.sleep(1000);
}
SwingUtilities.invokeLater(() -> {
sendCodeButton.setText("发送验证码");
sendCodeButton.setEnabled(true);
});
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}).start();
} else {
JOptionPane.showMessageDialog(ChangeCodeFrame.this,
"保存验证码失败", "错误", JOptionPane.ERROR_MESSAGE);
}
} else {
JOptionPane.showMessageDialog(ChangeCodeFrame.this,
"验证码发送失败,请检查邮箱地址或网络连接", "错误", JOptionPane.ERROR_MESSAGE);
}
}
}
private class ChangeCodeButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
String email = emailField.getText().trim();
String code = codeField.getText().trim();
String password = new String(passwordField.getPassword());
String confirmPassword = new String(confirmPasswordField.getPassword());
// 验证输入
if (email.isEmpty() || code.isEmpty() || password.isEmpty()) {
JOptionPane.showMessageDialog(ChangeCodeFrame.this,
"请填写所有字段", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
if (!password.equals(confirmPassword)) {
JOptionPane.showMessageDialog(ChangeCodeFrame.this,
"两次输入的密码不一致", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
if (!userService.validatePassword(password)) {
JOptionPane.showMessageDialog(ChangeCodeFrame.this,
"密码必须为6-10位且包含大小写字母和数字", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
// 使用新的重置密码方法
if (userService.resetPasswordWithCode(email, code, password)) {
JOptionPane.showMessageDialog(ChangeCodeFrame.this,
"密码重置成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
goBackToLogin();
} else {
JOptionPane.showMessageDialog(ChangeCodeFrame.this,
"重置失败,请检查验证码是否正确或是否已过期", "错误", JOptionPane.ERROR_MESSAGE);
}
}
}
private void goBackToLogin() {
loginFrame.setVisible(true);
this.dispose();
}
}

@ -63,8 +63,13 @@ public class LoginFrame extends JFrame{
registerButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
registerButton.addActionListener(e -> openRegisterFrame());
JButton changeCodeButton = new JButton("忘记密码?");
changeCodeButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
changeCodeButton.addActionListener(e -> openChangeCodeFrame());
buttonPanel.add(loginButton);
buttonPanel.add(registerButton);
buttonPanel.add(changeCodeButton);
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
@ -101,6 +106,12 @@ public class LoginFrame extends JFrame{
this.setVisible(false);
}
private void openChangeCodeFrame() {
ChangeCodeFrame changeCodeFrame = new ChangeCodeFrame(userService, this);
changeCodeFrame.setVisible(true);
this.setVisible(false);
}
private void openMainFrame(String email) {
User user = userService.getUser(email);
// 这里先简单显示一个消息,后续可以扩展为主界面

Loading…
Cancel
Save