From 6ed424f89e0bb7f0611b89a2ee947b6e0b1c089b Mon Sep 17 00:00:00 2001
From: 疯狂的狮子li <15040126243@163.com>
Date: 星期四, 30 三月 2023 10:19:17 +0800
Subject: [PATCH] add 增加 邮箱验证码发送接口 add 增加 邮箱登陆接口

---
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/AuthController.java                              |   18 +++++
 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/LoginType.java             |    5 +
 ruoyi-admin/src/main/resources/i18n/messages_en_US.properties                                       |    4 +
 ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java                                |   47 +++++++++++++++
 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml                       |   10 +++
 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/domain/model/SmsLoginBody.java   |    4 
 ruoyi-admin/src/main/resources/i18n/messages.properties                                             |    4 +
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/CaptchaController.java                           |   28 ++++++++
 ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java                 |   18 ++++++
 ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/domain/model/EmailLoginBody.java |   35 +++++++++++
 ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties                                       |    4 +
 11 files changed, 172 insertions(+), 5 deletions(-)

diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/AuthController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/AuthController.java
index 81af4df..9c0a638 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/AuthController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/AuthController.java
@@ -3,6 +3,7 @@
 import cn.dev33.satoken.annotation.SaIgnore;
 import cn.hutool.core.collection.CollUtil;
 import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.domain.model.EmailLoginBody;
 import com.ruoyi.common.core.domain.model.LoginBody;
 import com.ruoyi.common.core.domain.model.RegisterBody;
 import com.ruoyi.common.core.domain.model.SmsLoginBody;
@@ -62,7 +63,7 @@
     }
 
     /**
-     * 鐭俊鐧诲綍(绀轰緥)
+     * 鐭俊鐧诲綍
      *
      * @param body 鐧诲綍淇℃伅
      * @return 缁撴灉
@@ -77,6 +78,21 @@
     }
 
     /**
+     * 閭欢鐧诲綍
+     *
+     * @param body 鐧诲綍淇℃伅
+     * @return 缁撴灉
+     */
+    @PostMapping("/emailLogin")
+    public R<LoginVo> emailLogin(@Validated @RequestBody EmailLoginBody body) {
+        LoginVo loginVo = new LoginVo();
+        // 鐢熸垚浠ょ墝
+        String token = loginService.emailLogin(body.getTenantId(), body.getEmail(), body.getEmailCode());
+        loginVo.setToken(token);
+        return R.ok(loginVo);
+    }
+
+    /**
      * 灏忕▼搴忕櫥褰�(绀轰緥)
      *
      * @param xcxCode 灏忕▼搴廲ode
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/CaptchaController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/CaptchaController.java
index ab9c4d1..757caf5 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/CaptchaController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/CaptchaController.java
@@ -11,6 +11,8 @@
 import com.ruoyi.common.core.utils.SpringUtils;
 import com.ruoyi.common.core.utils.StringUtils;
 import com.ruoyi.common.core.utils.reflect.ReflectUtils;
+import com.ruoyi.common.mail.config.properties.MailProperties;
+import com.ruoyi.common.mail.utils.MailUtils;
 import com.ruoyi.common.redis.utils.RedisUtils;
 import com.ruoyi.common.sms.config.properties.SmsProperties;
 import com.ruoyi.common.sms.core.SmsTemplate;
@@ -46,6 +48,7 @@
 
     private final CaptchaProperties captchaProperties;
     private final SmsProperties smsProperties;
+    private final MailProperties mailProperties;
 
     /**
      * 鐭俊楠岃瘉鐮�
@@ -53,8 +56,7 @@
      * @param phonenumber 鐢ㄦ埛鎵嬫満鍙�
      */
     @GetMapping("/sms/code")
-    public R<Void> smsCaptcha(@NotBlank(message = "{user.phonenumber.not.blank}")
-                              String phonenumber) {
+    public R<Void> smsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) {
         if (!smsProperties.getEnabled()) {
             return R.fail("褰撳墠绯荤粺娌℃湁寮�鍚煭淇″姛鑳斤紒");
         }
@@ -75,6 +77,28 @@
     }
 
     /**
+     * 閭楠岃瘉鐮�
+     *
+     * @param email 閭
+     */
+    @GetMapping("/email/code")
+    public R<Void> emailCode(@NotBlank(message = "{user.email.not.blank}") String email) {
+        if (!mailProperties.getEnabled()) {
+            return R.fail("褰撳墠绯荤粺娌℃湁寮�鍚偖绠卞姛鑳斤紒");
+        }
+        String key = GlobalConstants.CAPTCHA_CODE_KEY + email;
+        String code = RandomUtil.randomNumbers(4);
+        RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
+        try {
+            MailUtils.sendText(email, "鐧诲綍楠岃瘉鐮�", "鎮ㄦ湰娆¢獙璇佺爜涓猴細" + code + "锛屾湁鏁堟�т负" + Constants.CAPTCHA_EXPIRATION + "鍒嗛挓锛岃灏藉揩濉啓銆�");
+        } catch (Exception e) {
+            log.error("楠岃瘉鐮佺煭淇″彂閫佸紓甯� => {}", e.getMessage());
+            return R.fail(e.getMessage());
+        }
+        return R.ok();
+    }
+
+    /**
      * 鐢熸垚楠岃瘉鐮�
      */
     @GetMapping("/code")
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java b/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java
index fece942..b853ab4 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/service/SysLoginService.java
@@ -112,6 +112,23 @@
         return StpUtil.getTokenValue();
     }
 
+    public String emailLogin(String tenantId, String email, String emailCode) {
+        // 鏍¢獙绉熸埛
+        checkTenant(tenantId);
+        // 閫氳繃鎵嬫満鍙锋煡鎵剧敤鎴�
+        SysUserVo user = loadUserByEmail(tenantId, email);
+
+        checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode));
+        // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser
+        LoginUser loginUser = buildLoginUser(user);
+        // 鐢熸垚token
+        LoginHelper.loginByDevice(loginUser, DeviceType.APP);
+
+        recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
+        recordLoginInfo(user.getUserId());
+        return StpUtil.getTokenValue();
+    }
+
 
     public String xcxLogin(String xcxCode) {
         // xcxCode 涓� 灏忕▼搴忚皟鐢� wx.login 鎺堟潈鍚庤幏鍙�
@@ -185,6 +202,18 @@
     }
 
     /**
+     * 鏍¢獙閭楠岃瘉鐮�
+     */
+    private boolean validateEmailCode(String tenantId, String email, String emailCode) {
+        String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email);
+        if (StringUtils.isBlank(code)) {
+            recordLogininfor(tenantId, email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
+            throw new CaptchaExpireException();
+        }
+        return code.equals(emailCode);
+    }
+
+    /**
      * 鏍¢獙楠岃瘉鐮�
      *
      * @param username 鐢ㄦ埛鍚�
@@ -241,6 +270,24 @@
         return userMapper.selectUserByPhonenumber(phonenumber);
     }
 
+    private SysUserVo loadUserByEmail(String tenantId, String email) {
+        SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
+            .select(SysUser::getPhonenumber, SysUser::getStatus)
+            .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId)
+            .eq(SysUser::getEmail, email));
+        if (ObjectUtil.isNull(user)) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", email);
+            throw new UserException("user.not.exists", email);
+        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", email);
+            throw new UserException("user.blocked", email);
+        }
+        if (TenantHelper.isEnable()) {
+            return userMapper.selectTenantUserByEmail(email, tenantId);
+        }
+        return userMapper.selectUserByEmail(email);
+    }
+
     private SysUserVo loadUserByOpenid(String openid) {
         // 浣跨敤 openid 鏌ヨ缁戝畾鐢ㄦ埛 濡傛湭缁戝畾鐢ㄦ埛 鍒欐牴鎹笟鍔¤嚜琛屽鐞� 渚嬪 鍒涘缓榛樿鐢ㄦ埛
         // todo 鑷瀹炵幇 userService.selectUserByOpenid(openid);
diff --git a/ruoyi-admin/src/main/resources/i18n/messages.properties b/ruoyi-admin/src/main/resources/i18n/messages.properties
index 3a5eeac..4f2da28 100644
--- a/ruoyi-admin/src/main/resources/i18n/messages.properties
+++ b/ruoyi-admin/src/main/resources/i18n/messages.properties
@@ -18,6 +18,7 @@
 user.password.length.valid=鐢ㄦ埛瀵嗙爜闀垮害蹇呴』鍦▄min}鍒皗max}涓瓧绗︿箣闂�
 user.password.not.valid=* 5-50涓瓧绗�
 user.email.not.valid=閭鏍煎紡閿欒
+user.email.not.blank=閭涓嶈兘涓虹┖
 user.phonenumber.not.blank=鐢ㄦ埛鎵嬫満鍙蜂笉鑳戒负绌�
 user.mobile.phone.number.not.valid=鎵嬫満鍙锋牸寮忛敊璇�
 user.login.success=鐧诲綍鎴愬姛
@@ -42,6 +43,9 @@
 sms.code.not.blank=鐭俊楠岃瘉鐮佷笉鑳戒负绌�
 sms.code.retry.limit.count=鐭俊楠岃瘉鐮佽緭鍏ラ敊璇瘂0}娆�
 sms.code.retry.limit.exceed=鐭俊楠岃瘉鐮佽緭鍏ラ敊璇瘂0}娆★紝甯愭埛閿佸畾{1}鍒嗛挓
+email.code.not.blank=閭楠岃瘉鐮佷笉鑳戒负绌�
+email.code.retry.limit.count=閭楠岃瘉鐮佽緭鍏ラ敊璇瘂0}娆�
+email.code.retry.limit.exceed=閭楠岃瘉鐮佽緭鍏ラ敊璇瘂0}娆★紝甯愭埛閿佸畾{1}鍒嗛挓
 xcx.code.not.blank=灏忕▼搴廲ode涓嶈兘涓虹┖
 ##绉熸埛
 tenant.number.not.blank=绉熸埛缂栧彿涓嶈兘涓虹┖
diff --git a/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
index 7568f68..0c738a3 100644
--- a/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
+++ b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
@@ -18,6 +18,7 @@
 user.password.length.valid=Password length must be between {min} and {max} characters
 user.password.not.valid=* 5-50 characters
 user.email.not.valid=Mailbox format error
+user.email.not.blank=Mailbox cannot be blank
 user.phonenumber.not.blank=Phone number cannot be blank
 user.mobile.phone.number.not.valid=Phone number format error
 user.login.success=Login successful
@@ -42,6 +43,9 @@
 sms.code.not.blank=Sms code cannot be blank
 sms.code.retry.limit.count=Sms code input error {0} times
 sms.code.retry.limit.exceed=Sms code input error {0} times, account locked for {1} minutes
+email.code.not.blank=Email code cannot be blank
+email.code.retry.limit.count=Email code input error {0} times
+email.code.retry.limit.exceed=Email code input error {0} times, account locked for {1} minutes
 xcx.code.not.blank=Mini program code cannot be blank
 ##绉熸埛
 tenant.number.not.blank=Tenant number cannot be blank
diff --git a/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
index 3a5eeac..4f2da28 100644
--- a/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
+++ b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
@@ -18,6 +18,7 @@
 user.password.length.valid=鐢ㄦ埛瀵嗙爜闀垮害蹇呴』鍦▄min}鍒皗max}涓瓧绗︿箣闂�
 user.password.not.valid=* 5-50涓瓧绗�
 user.email.not.valid=閭鏍煎紡閿欒
+user.email.not.blank=閭涓嶈兘涓虹┖
 user.phonenumber.not.blank=鐢ㄦ埛鎵嬫満鍙蜂笉鑳戒负绌�
 user.mobile.phone.number.not.valid=鎵嬫満鍙锋牸寮忛敊璇�
 user.login.success=鐧诲綍鎴愬姛
@@ -42,6 +43,9 @@
 sms.code.not.blank=鐭俊楠岃瘉鐮佷笉鑳戒负绌�
 sms.code.retry.limit.count=鐭俊楠岃瘉鐮佽緭鍏ラ敊璇瘂0}娆�
 sms.code.retry.limit.exceed=鐭俊楠岃瘉鐮佽緭鍏ラ敊璇瘂0}娆★紝甯愭埛閿佸畾{1}鍒嗛挓
+email.code.not.blank=閭楠岃瘉鐮佷笉鑳戒负绌�
+email.code.retry.limit.count=閭楠岃瘉鐮佽緭鍏ラ敊璇瘂0}娆�
+email.code.retry.limit.exceed=閭楠岃瘉鐮佽緭鍏ラ敊璇瘂0}娆★紝甯愭埛閿佸畾{1}鍒嗛挓
 xcx.code.not.blank=灏忕▼搴廲ode涓嶈兘涓虹┖
 ##绉熸埛
 tenant.number.not.blank=绉熸埛缂栧彿涓嶈兘涓虹┖
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/domain/model/EmailLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/domain/model/EmailLoginBody.java
new file mode 100644
index 0000000..6459673
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/domain/model/EmailLoginBody.java
@@ -0,0 +1,35 @@
+package com.ruoyi.common.core.domain.model;
+
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+
+/**
+ * 鐭俊鐧诲綍瀵硅薄
+ *
+ * @author Lion Li
+ */
+
+@Data
+public class EmailLoginBody {
+
+    /**
+     * 绉熸埛ID
+     */
+    @NotBlank(message = "{tenant.number.not.blank}")
+    private String tenantId;
+
+    /**
+     * 閭
+     */
+    @NotBlank(message = "{user.email.not.blank}")
+    @Email(message = "{user.email.not.valid}")
+    private String email;
+
+    /**
+     * 閭code
+     */
+    @NotBlank(message = "{email.code.not.blank}")
+    private String emailCode;
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/domain/model/SmsLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/domain/model/SmsLoginBody.java
index 3b25fce..70df20d 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/domain/model/SmsLoginBody.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/domain/model/SmsLoginBody.java
@@ -20,13 +20,13 @@
     private String tenantId;
 
     /**
-     * 鐢ㄦ埛鍚�
+     * 鎵嬫満鍙�
      */
     @NotBlank(message = "{user.phonenumber.not.blank}")
     private String phonenumber;
 
     /**
-     * 鐢ㄦ埛瀵嗙爜
+     * 鐭俊code
      */
     @NotBlank(message = "{sms.code.not.blank}")
     private String smsCode;
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/LoginType.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/LoginType.java
index fcd48df..dbd6de1 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/LoginType.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/LoginType.java
@@ -23,6 +23,11 @@
     SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"),
 
     /**
+     * 閭鐧诲綍
+     */
+    EMAIL("email.code.retry.limit.exceed", "email.code.retry.limit.count"),
+
+    /**
      * 灏忕▼搴忕櫥褰�
      */
     XCX("", "");
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java
index 84b26fd..2aacf48 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java
@@ -79,6 +79,14 @@
     SysUserVo selectUserByPhonenumber(String phonenumber);
 
     /**
+     * 閫氳繃閭鏌ヨ鐢ㄦ埛
+     *
+     * @param email 閭
+     * @return 鐢ㄦ埛瀵硅薄淇℃伅
+     */
+    SysUserVo selectUserByEmail(String email);
+
+    /**
      * 閫氳繃鐢ㄦ埛鍚嶆煡璇㈢敤鎴�(涓嶈蛋绉熸埛鎻掍欢)
      *
      * @param userName 鐢ㄦ埛鍚�
@@ -99,6 +107,16 @@
     SysUserVo selectTenantUserByPhonenumber(String phonenumber, String tenantId);
 
     /**
+     * 閫氳繃閭鏌ヨ鐢ㄦ埛(涓嶈蛋绉熸埛鎻掍欢)
+     *
+     * @param email    閭
+     * @param tenantId 绉熸埛id
+     * @return 鐢ㄦ埛瀵硅薄淇℃伅
+     */
+    @InterceptorIgnore(tenantLine = "true")
+    SysUserVo selectTenantUserByEmail(String email, String tenantId);
+
+    /**
      * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛
      *
      * @param userId 鐢ㄦ埛ID
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
index 481c17a..92d8c9e 100644
--- a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -102,6 +102,11 @@
         where u.del_flag = '0' and u.phonenumber = #{phonenumber}
     </select>
 
+    <select id="selectUserByEmail" parameterType="String" resultMap="SysUserResult">
+        <include refid="selectUserVo"/>
+        where u.del_flag = '0' and u.email = #{email}
+    </select>
+
     <select id="selectTenantUserByUserName" parameterType="String" resultMap="SysUserResult">
         <include refid="selectUserVo"/>
         where u.del_flag = '0' and u.user_name = #{userName} and u.tenant_id = #{tenantId}
@@ -112,6 +117,11 @@
         where u.del_flag = '0' and u.phonenumber = #{phonenumber} and u.tenant_id = #{tenantId}
     </select>
 
+    <select id="selectTenantUserByEmail" parameterType="String" resultMap="SysUserResult">
+        <include refid="selectUserVo"/>
+        where u.del_flag = '0' and u.email = #{email} and u.tenant_id = #{tenantId}
+    </select>
+
     <select id="selectUserById" parameterType="Long" resultMap="SysUserResult">
         <include refid="selectUserVo"/>
         where u.del_flag = '0' and u.user_id = #{userId}

--
Gitblit v1.9.3