From 7884e56895a0a26ddcf936945c930dcbf7f06edf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E6=98=A0=E6=B1=9F?= <15547749+cyj-050209@user.noreply.gitee.com> Date: Thu, 9 Oct 2025 02:48:02 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BF=98=E8=AE=B0=E5=AF=86?= =?UTF-8?q?=E7=A0=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/vcs.xml | 6 + data/users.json | 4 +- .../mathlearning/service/UserService.java | 47 ++++ .../java/mathlearning/ui/ChangeCodeFrame.java | 226 ++++++++++++++++++ src/main/java/mathlearning/ui/LoginFrame.java | 11 + 5 files changed, 292 insertions(+), 2 deletions(-) create mode 100644 .idea/vcs.xml create mode 100644 src/main/java/mathlearning/ui/ChangeCodeFrame.java diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/data/users.json b/data/users.json index 07dc93d..d478b7e 100644 --- a/data/users.json +++ b/data/users.json @@ -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 } ] \ No newline at end of file diff --git a/src/main/java/mathlearning/service/UserService.java b/src/main/java/mathlearning/service/UserService.java index 37b4de9..978cf3c 100644 --- a/src/main/java/mathlearning/service/UserService.java +++ b/src/main/java/mathlearning/service/UserService.java @@ -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+_.-]+@(.+)$"); } diff --git a/src/main/java/mathlearning/ui/ChangeCodeFrame.java b/src/main/java/mathlearning/ui/ChangeCodeFrame.java new file mode 100644 index 0000000..cace250 --- /dev/null +++ b/src/main/java/mathlearning/ui/ChangeCodeFrame.java @@ -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(); + } +} diff --git a/src/main/java/mathlearning/ui/LoginFrame.java b/src/main/java/mathlearning/ui/LoginFrame.java index 7d1c365..8084d74 100644 --- a/src/main/java/mathlearning/ui/LoginFrame.java +++ b/src/main/java/mathlearning/ui/LoginFrame.java @@ -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); // 这里先简单显示一个消息,后续可以扩展为主界面