zqy
2025-10-14 4502f650f4816e55b5c7bf751ffce3aa0dce72dd
找回密码功能
12个文件已修改
2个文件已添加
326 ■■■■■ 已修改文件
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/zhang/ZInfoUserController.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/resources/application.yml 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/EmailService.java 177 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VerificationCodeService.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhang-content/pom.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
zhang-content/src/main/java/com/ruoyi/domain/sysUserAndUserInfo.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
@@ -9,7 +9,10 @@
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.framework.web.domain.server.Sys;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.impl.EmailService;
import com.ruoyi.system.service.impl.VerificationCodeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.constant.Constants;
@@ -41,6 +44,12 @@
    @Autowired
    private ISysUserService userService;
    @Autowired
    private EmailService emailService;
    @Autowired
    private VerificationCodeService codeService;
    /**
     * 登录方法
@@ -150,4 +159,44 @@
        System.out.println(menus);
        return AjaxResult.success(menuService.buildMenus(menus));//这里之后就封装好了发给前端的vo
    }
    // 步骤1:请求发送验证码
    @PostMapping("/getCode")
    public AjaxResult requestPasswordReset(@RequestBody SysUser sysUser) {
        // 验证账号和邮箱是否匹配
        SysUser user = userService.checkEmail(sysUser.getNickName(),sysUser.getEmail());
        if (user == null) {
            return AjaxResult.error("账号或邮箱不匹配");
        }
        // 生成并发送验证码
        String verificationCode = codeService.generateCode();
        codeService.saveCode(sysUser.getNickName(), verificationCode);
        emailService.sendVerificationCode(sysUser.getEmail(), verificationCode);
        return AjaxResult.success("验证码已发送至您的邮箱");
    }
    // 步骤2:验证验证码并重置密码
    @PostMapping("/reset")
    public AjaxResult resetPassword(@RequestParam String nickName,
                                           @RequestParam String verificationCode,
                                           @RequestParam String newPassword) {
        // 验证验证码
        if (!codeService.validateCode(nickName, verificationCode)) {
            return AjaxResult.error("验证码无效或已过期");
        }
        // 更新密码
        SysUser user = userService.selectUserByNickName(nickName);
        System.out.println(user);
        if (user != null) {
            newPassword = SecurityUtils.encryptPassword(newPassword);
            user.setPassword(newPassword);
            userService.updateUser(user);// 实际应用中应对密码加密
            return AjaxResult.success("密码重置成功");
        }
        return AjaxResult.error("用户不存在");
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
@@ -197,7 +197,8 @@
        us.setRoleId(user.getRoleId());      // 角色ID(102=家庭成员)
        us.setSex(user.getSex());            // 性别(0男/1女)
        us.setStatus(user.getStatus());      // 账户状态(启用/禁用)
        us.setRemark(user.getRemark());      // 备注信息
        us.setRemark(user.getRemark());
        us.setEmail(user.getEmail());// 备注信息
        userService.updateUser(us);          // 执行SysUser表更新
        // ===== 2. 家庭成员专属处理(仅角色ID=102时执行)=====
@@ -209,7 +210,8 @@
            infoUser.setNickName(user.getNickName());      // 当前昵称
            infoUser.setIsMyFamily(user.getIsMyFamily()); // 家庭成员标记(0/1)
            infoUser.setMomId(user.getMid());             // 母亲ID(可为空)
            infoUser.setFatherId(user.getFid());           // 父亲ID(可为空)
            infoUser.setFatherId(user.getFid());
            infoUser.setEmail(user.getEmail());// 父亲ID(可为空)
            // 婚姻状态空值保护(0未婚/1已婚/2离婚)
            infoUser.setMaritalStatus(user.getMaritalStatus() == null ? null : user.getMaritalStatus());
            // 性别格式转换(String → Integer)
@@ -412,6 +414,7 @@
        user.setUpdateBy(userAll.getUpdateBy());    // 更新人
        user.setClanId(userAll.getClanId());        // 家族ID
        user.setPaid(userAll.getPaid());
        user.setEmail(userAll.getEmail());
        // ===================== 2. 唯一性校验(登录名/手机号/邮箱) =====================
        // 2.1 登录名校验
@@ -451,7 +454,7 @@
            infoUser.setNickName(userAll.getNickName()); // 当前昵称
            infoUser.setOldName(userAll.getUserName());  // 历史名称(保留记录)
            infoUser.setPhoneNumber(userAll.getPhonenumber()); // 联系方式
            infoUser.setEmail(userAll.getEmail());
            String originalString=userAll.getUserName()+"-"+userAll.getPhonenumber();
            String uniqueId = UUID.nameUUIDFromBytes(originalString.getBytes()).toString();
ruoyi-admin/src/main/java/com/ruoyi/web/controller/zhang/ZInfoUserController.java
@@ -192,6 +192,7 @@
        user.setSex(zInfoUser.getSex()+"");
        user.setUserName(zInfoUser.getOldName());
        user.setPhonenumber(zInfoUser.getPhoneNumber());
        user.setEmail(zInfoUser.getEmail());
        String oriUaid = zInfoUser.getUaid();
        String originalString = zInfoUser.getOldName()+"-"+zInfoUser.getPhoneNumber();
ruoyi-admin/src/main/resources/application.yml
@@ -102,6 +102,24 @@
        max-active: 8
        # #连接池最大阻塞等待时间(使用负值表示没有限制)
        max-wait: -1ms
  #邮箱配置
  mail:
    host: smtp.qq.com
    port: 587
    #邮箱
    username: 3224414357@qq.com
    #授权码
    password: wmsreabbwlmacjhe
    protocol: smtp
    properties:
#      mail.debug: true
      mail.smtp.auth: true
      mail.smtp.starttls.enable: true
      mail.smtp.starttls.required: true
      mail.smtp.ehlo: true # 关键修复
      mail.smtp.ssl.trust: smtp.qq.com
      mail.smtp.ssl.protocols: TLSv1.2
    default-encoding: UTF-8
# token配置
token:
@@ -158,3 +176,4 @@
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
@@ -111,7 +111,7 @@
                // 过滤请求
                .authorizeRequests()
                // 对于登录login 注册register 验证码captchaImage 允许匿名访问
                .antMatchers("/login", "/register", "/captchaImage","/qrCode/getInf","/common/downLoadFile").permitAll()
                .antMatchers("/login", "/register", "/captchaImage","/qrCode/getInf","/common/downLoadFile","/getCode","/reset").permitAll()
                // 静态资源,可匿名访问
                .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
                .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java
@@ -287,4 +287,7 @@
        sysUser.setLoginDate(DateUtils.getNowDate());
        userService.updateUserProfile(sysUser);
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java
@@ -148,4 +148,13 @@
     * @return 结果
     */
    public SysUser checkEmailUnique(String email);
    /**
     * 匹配邮箱
     * @param nickName 用户账号名
     * @param email 用户邮箱
     * @return 结果
     */
    SysUser checkEmail(@Param("nickName") String nickName,@Param("email") String email);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java
@@ -236,4 +236,12 @@
     * @return 结果
     */
    public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName);
    /**
     * 匹配邮箱
     * @param nickName 用户账号名
     * @param email 用户邮箱
     * @return 结果
     */
    SysUser checkEmail(String nickName,String email);
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/EmailService.java
New file
@@ -0,0 +1,177 @@
package com.ruoyi.system.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
@Service
public class EmailService {
    @Autowired
    private JavaMailSender mailSender;
    @Value("${spring.mail.username}")
    private String fromEmail;
    public void sendVerificationCode(String toEmail, String verificationCode) {
        try {
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
            helper.setFrom(new InternetAddress(fromEmail, "本嘟嘟家网"));
            helper.setTo(toEmail);
            helper.setSubject("本嘟嘟家网 - 登录验证码");
            // 构建HTML内容
            String htmlContent = buildVerificationEmail(verificationCode);
            helper.setText(htmlContent, true); // true表示内容为HTML
            mailSender.send(message);
        } catch (Exception e) {
            throw new RuntimeException("邮件发送失败", e);
        }
    }
    private String buildVerificationEmail(String verificationCode) {
        return "<!DOCTYPE html>\n" +
                "<html>\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\">\n" +
                "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n" +
                "    <title>本嘟嘟家网 - 安全验证码</title>\n" +
                "    <style>\n" +
                "        body {\n" +
                "            font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;\n" +
                "            line-height: 1.6;\n" +
                "            color: #333333;\n" +
                "            background-color: #f5f7fa;\n" +
                "            margin: 0;\n" +
                "            padding: 0;\n" +
                "        }\n" +
                "        .email-container {\n" +
                "            max-width: 600px;\n" +
                "            margin: 20px auto;\n" +
                "            background-color: #ffffff;\n" +
                "            border-radius: 8px;\n" +
                "            box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);\n" +
                "            overflow: hidden;\n" +
                "        }\n" +
                "        .header {\n" +
                "            background: linear-gradient(135deg, #1e88e5, #0d47a1);\n" +
                "            padding: 25px 30px;\n" +
                "            text-align: center;\n" +
                "            color: white;\n" +
                "        }\n" +
                "        .header h1 {\n" +
                "            margin: 0;\n" +
                "            font-size: 22px;\n" +
                "            font-weight: 600;\n" +
                "            letter-spacing: 0.5px;\n" +
                "        }\n" +
                "        .content {\n" +
                "            padding: 30px;\n" +
                "        }\n" +
                "        .security-notice {\n" +
                "            background-color: #fff8e1;\n" +
                "            border-left: 4px solid #ffc107;\n" +
                "            padding: 15px;\n" +
                "            margin-bottom: 25px;\n" +
                "            border-radius: 4px;\n" +
                "            font-size: 14px;\n" +
                "            color: #5d4037;\n" +
                "        }\n" +
                "        .verification-section {\n" +
                "            text-align: center;\n" +
                "            margin: 30px 0;\n" +
                "            padding: 20px;\n" +
                "            background-color: #f0f7ff;\n" +
                "            border-radius: 8px;\n" +
                "        }\n" +
                "        .code-label {\n" +
                "            font-size: 16px;\n" +
                "            color: #1565c0;\n" +
                "            margin-bottom: 15px;\n" +
                "        }\n" +
                "        .code-display {\n" +
                "            display: inline-block;\n" +
                "            background: linear-gradient(to right, #2196f3, #21cbf3);\n" +
                "            color: white;\n" +
                "            font-size: 36px;\n" +
                "            font-weight: 700;\n" +
                "            padding: 15px 40px;\n" +
                "            border-radius: 8px;\n" +
                "            letter-spacing: 8px;\n" +
                "            box-shadow: 0 4px 15px rgba(33, 150, 243, 0.3);\n" +
                "            margin: 15px 0;\n" +
                "            text-decoration: none;\n" +
                "        }\n" +
                "        .instructions {\n" +
                "            font-size: 15px;\n" +
                "            color: #555555;\n" +
                "            margin-bottom: 25px;\n" +
                "            line-height: 1.7;\n" +
                "        }\n" +
                "        .validity {\n" +
                "            background-color: #e3f2fd;\n" +
                "            padding: 15px;\n" +
                "            border-radius: 6px;\n" +
                "            text-align: center;\n" +
                "            font-size: 14px;\n" +
                "            color: #0d47a1;\n" +
                "            margin-top: 25px;\n" +
                "        }\n" +
                "        .footer {\n" +
                "            text-align: center;\n" +
                "            padding: 20px;\n" +
                "            background-color: #f5f7fa;\n" +
                "            color: #78909c;\n" +
                "            font-size: 13px;\n" +
                "            border-top: 1px solid #e0e0e0;\n" +
                "        }\n" +
                "        .footer p {\n" +
                "            margin: 5px 0;\n" +
                "        }\n" +
                "        .highlight {\n" +
                "            color: #d32f2f;\n" +
                "            font-weight: 600;\n" +
                "        }\n" +
                "    </style>\n" +
                "</head>\n" +
                "<body>\n" +
                "    <div class=\"email-container\">\n" +
                "        <div class=\"header\">\n" +
                "            <h1>本嘟嘟家网 - 安全验证</h1>\n" +
                "        </div>\n" +
                "        \n" +
                "        <div class=\"content\">\n" +
                "            <div class=\"security-notice\">\n" +
                "                <strong>安全提示:</strong> 您正在登录本嘟嘟家网,验证码请勿告知他人,泄露会导致账号被盗,使家族及个人信息泄露。\n" +
                "            </div>\n" +
                "            \n" +
                "            <p class=\"instructions\">请使用以下验证码完成登录验证:</p>\n" +
                "            \n" +
                "            <div class=\"verification-section\">\n" +
                "                <div class=\"code-label\">您的验证码</div>\n" +
                "                <div class=\"code-display\">" + verificationCode + "</div>\n" +
                "                <p class=\"instructions\">请将上述验证码输入到登录页面的验证码输入框中</p>\n" +
                "            </div>\n" +
                "            \n" +
                "            <div class=\"validity\">\n" +
                "                <strong>请注意:</strong> 此验证码将在 <strong>5分钟</strong> 后失效,请尽快使用。\n" +
                "            </div>\n" +
                "        </div>\n" +
                "        \n" +
                "        <div class=\"footer\">\n" +
                "            <p>此为系统自动发送邮件,请勿直接回复</p>\n" +
                "            <p>如果您未进行此操作,请忽略此邮件或联系客服</p>\n" +
                "            <p>© 2023 本嘟嘟家网 版权所有</p>\n" +
                "        </div>\n" +
                "    </div>\n" +
                "</body>\n" +
                "</html>";
    }
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
@@ -659,6 +659,14 @@
    }
    @Override
    public SysUser checkEmail(String nickName, String email) {
        System.out.println(nickName);
         SysUser sysUser = userMapper.checkEmail(nickName, email);
        System.out.println(sysUser);
        return sysUser ;
    }
    @Override
    public boolean saveBatch(Collection<SysUser> entityList, int batchSize) {
        return false;
    }
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/VerificationCodeService.java
New file
@@ -0,0 +1,30 @@
package com.ruoyi.system.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.Random;
import java.util.concurrent.TimeUnit;
@Service
public class VerificationCodeService {
    @Autowired
    private StringRedisTemplate redisTemplate;
    public String generateCode() {
        Random random = new Random();
        return String.format("%04d", random.nextInt(10000));
    }
    public void saveCode(String username, String code) {
        String key = "verification_code:" + username;
        redisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES); // 5分钟有效
    }
    public boolean validateCode(String username, String inputCode) {
        String key = "verification_code:" + username;
        String storedCode = redisTemplate.opsForValue().get(key);
        return inputCode.equals(storedCode);
    }
}
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -199,6 +199,10 @@
        select user_id, email from sys_user where email = #{email} and del_flag = '0' limit 1
    </select>
    <select id="checkEmail" parameterType="SysUser" resultMap="SysUserResult">
        select user_id, email,nick_name from sys_user where email = #{email} and nick_name = #{nickName} and del_flag = '0' limit 1
    </select>
    <insert id="insertUser" parameterType="SysUser" useGeneratedKeys="true" keyProperty="userId">
         insert into sys_user(
             <if test="userId != null and userId != 0">user_id,</if>
zhang-content/pom.xml
@@ -101,6 +101,11 @@
            <version>2.8.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>
    </dependencies>
    <build>
zhang-content/src/main/java/com/ruoyi/domain/sysUserAndUserInfo.java
@@ -33,6 +33,8 @@
    @Excel(name = "用户昵称")
    private String nickName;
    private String email;