ソースを参照

add 增加 邮箱验证码发送接口
add 增加 邮箱登陆接口

疯狂的狮子li 3 年 前
コミット
113ad796f0

+ 8 - 0
ruoyi-api/ruoyi-api-system/src/main/java/com/ruoyi/system/api/RemoteUserService.java

@@ -28,6 +28,14 @@ public interface RemoteUserService {
      */
     LoginUser getUserInfoByPhonenumber(String phonenumber) throws UserException;
 
+    /**
+     * 通过邮箱查询用户信息
+     *
+     * @param email 邮箱
+     * @return 结果
+     */
+    LoginUser getUserInfoByEmail(String email) throws UserException;
+
     /**
      * 通过openid查询用户信息
      *

+ 16 - 0
ruoyi-auth/src/main/java/com/ruoyi/auth/controller/TokenController.java

@@ -1,5 +1,6 @@
 package com.ruoyi.auth.controller;
 
+import com.ruoyi.auth.form.EmailLoginBody;
 import com.ruoyi.auth.form.LoginBody;
 import com.ruoyi.auth.form.RegisterBody;
 import com.ruoyi.auth.form.SmsLoginBody;
@@ -58,6 +59,21 @@ public class TokenController {
         return R.ok(ajax);
     }
 
+    /**
+     * 邮件登录
+     *
+     * @param body 登录信息
+     * @return 结果
+     */
+    @PostMapping("/emailLogin")
+    public R<Map<String, Object>> emailLogin(@Validated @RequestBody EmailLoginBody body) {
+        Map<String, Object> ajax = new HashMap<>();
+        // 生成令牌
+        String token = sysLoginService.emailLogin(body.getEmail(), body.getEmailCode());
+        ajax.put(Constants.ACCESS_TOKEN, token);
+        return R.ok(ajax);
+    }
+
     /**
      * 小程序登录(示例)
      *

+ 30 - 0
ruoyi-auth/src/main/java/com/ruoyi/auth/form/EmailLoginBody.java

@@ -0,0 +1,30 @@
+package com.ruoyi.auth.form;
+
+import lombok.Data;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 短信登录对象
+ *
+ * @author Lion Li
+ */
+
+@Data
+public class EmailLoginBody {
+
+    /**
+     * 邮箱
+     */
+    @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;
+
+}

+ 2 - 2
ruoyi-auth/src/main/java/com/ruoyi/auth/form/SmsLoginBody.java

@@ -14,13 +14,13 @@ import javax.validation.constraints.NotBlank;
 public class SmsLoginBody {
 
     /**
-     * 用户名
+     * 手机号
      */
     @NotBlank(message = "{user.phonenumber.not.blank}")
     private String phonenumber;
 
     /**
-     * 用户密码
+     * 短信code
      */
     @NotBlank(message = "{sms.code.not.blank}")
     private String smsCode;

+ 24 - 0
ruoyi-auth/src/main/java/com/ruoyi/auth/service/SysLoginService.java

@@ -78,6 +78,18 @@ public class SysLoginService {
         return StpUtil.getTokenValue();
     }
 
+    public String emailLogin(String email, String emailCode) {
+        // 通过邮箱查找用户
+        LoginUser userInfo = remoteUserService.getUserInfoByEmail(email);
+
+        checkLogin(LoginType.EMAIL, userInfo.getUsername(), () -> !validateEmailCode(email, emailCode));
+        // 生成token
+        LoginHelper.loginByDevice(userInfo, DeviceType.APP);
+
+        recordLogininfor(userInfo.getUsername(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
+        return StpUtil.getTokenValue();
+    }
+
     public String xcxLogin(String xcxCode) {
         // xcxCode 为 小程序调用 wx.login 授权后获取
         // todo 自行实现 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid
@@ -171,6 +183,18 @@ public class SysLoginService {
         return code.equals(smsCode);
     }
 
+    /**
+     * 校验邮箱验证码
+     */
+    private boolean validateEmailCode(String email, String emailCode) {
+        String code = RedisUtils.getCacheObject(CacheConstants.CAPTCHA_CODE_KEY + email);
+        if (StringUtils.isBlank(code)) {
+            recordLogininfor(email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
+            throw new CaptchaExpireException();
+        }
+        return code.equals(emailCode);
+    }
+
     /**
      * 登录校验
      */

+ 5 - 0
ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/LoginType.java

@@ -22,6 +22,11 @@ public enum LoginType {
      */
     SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"),
 
+    /**
+     * 邮箱登录
+     */
+    EMAIL("email.code.retry.limit.exceed", "email.code.retry.limit.count"),
+
     /**
      * 小程序登录
      */

+ 4 - 0
ruoyi-common/ruoyi-common-core/src/main/resources/i18n/messages.properties

@@ -18,6 +18,7 @@ user.password.not.blank=用户密码不能为空
 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,4 +43,7 @@ rate.limiter.message=访问过于频繁,请稍候再试
 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=小程序code不能为空

+ 4 - 0
ruoyi-common/ruoyi-common-core/src/main/resources/i18n/messages_en_US.properties

@@ -18,6 +18,7 @@ user.password.not.blank=Password cannot be empty
 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,4 +43,7 @@ rate.limiter.message=Visit too frequently, please try again later
 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

+ 4 - 0
ruoyi-common/ruoyi-common-core/src/main/resources/i18n/messages_zh_CN.properties

@@ -18,6 +18,7 @@ user.password.not.blank=用户密码不能为空
 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,4 +43,7 @@ rate.limiter.message=访问过于频繁,请稍候再试
 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=小程序code不能为空

+ 1 - 1
ruoyi-common/ruoyi-common-mail/src/main/java/com/ruoyi/common/mail/config/properties/MailProperties.java

@@ -15,7 +15,7 @@ public class MailProperties {
     /**
      * 过滤开关
      */
-    private String enabled;
+    private Boolean enabled;
 
     /**
      * SMTP服务器域名

+ 58 - 0
ruoyi-modules/ruoyi-resource/src/main/java/com/ruoyi/resource/controller/SysEmailController.java

@@ -0,0 +1,58 @@
+package com.ruoyi.resource.controller;
+
+
+import cn.hutool.core.util.RandomUtil;
+import com.ruoyi.common.core.constant.CacheConstants;
+import com.ruoyi.common.core.constant.Constants;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.web.controller.BaseController;
+import com.ruoyi.common.mail.config.properties.MailProperties;
+import com.ruoyi.common.mail.utils.MailUtils;
+import com.ruoyi.common.redis.utils.RedisUtils;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.constraints.NotBlank;
+import java.time.Duration;
+
+/**
+ * 邮件功能
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/email")
+public class SysEmailController extends BaseController {
+
+    private final MailProperties mailProperties;
+
+    /**
+     * 邮箱验证码
+     *
+     * @param email 邮箱
+     */
+    @GetMapping("/code")
+    public R<Void> emailCode(@NotBlank(message = "{user.email.not.blank}") String email) {
+        if (!mailProperties.getEnabled()) {
+            return R.fail("当前系统没有开启邮箱功能!");
+        }
+        String key = CacheConstants.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();
+    }
+
+}

+ 15 - 0
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/dubbo/RemoteUserServiceImpl.java

@@ -66,6 +66,21 @@ public class RemoteUserServiceImpl implements RemoteUserService {
         return buildLoginUser(userMapper.selectUserByPhonenumber(phonenumber));
     }
 
+    @Override
+    public LoginUser getUserInfoByEmail(String email) throws UserException {
+        SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
+            .select(SysUser::getPhonenumber, SysUser::getStatus)
+            .eq(SysUser::getEmail, email));
+        if (ObjectUtil.isNull(user)) {
+            throw new UserException("user.not.exists", email);
+        }
+        if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+            throw new UserException("user.blocked", email);
+        }
+        // 此处可根据登录用户的数据不同 自行创建 loginUser
+        return buildLoginUser(userMapper.selectUserByEmail(email));
+    }
+
     @Override
     public XcxLoginUser getUserInfoByOpenid(String openid) throws UserException {
         // todo 自行实现 userService.selectUserByOpenid(openid);

+ 8 - 0
ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java

@@ -77,6 +77,14 @@ public interface SysUserMapper extends BaseMapperPlus<SysUserMapper, SysUser, Sy
      */
     SysUser selectUserByPhonenumber(String phonenumber);
 
+    /**
+     * 通过邮箱查询用户
+     *
+     * @param email 邮箱
+     * @return 用户对象信息
+     */
+    SysUser selectUserByEmail(String email);
+
     /**
      * 通过用户ID查询用户
      *

+ 5 - 0
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml

@@ -126,6 +126,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         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="selectUserById" parameterType="Long" resultMap="SysUserResult">
 		<include refid="selectUserVo"/>
 		where u.del_flag = '0' and u.user_id = #{userId}