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;