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 å°ç¨åºcode 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") 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); 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=å°ç¨åºcodeä¸è½ä¸ºç©º ##ç§æ· tenant.number.not.blank=ç§æ·ç¼å·ä¸è½ä¸ºç©º 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 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=å°ç¨åºcodeä¸è½ä¸ºç©º ##ç§æ· tenant.number.not.blank=ç§æ·ç¼å·ä¸è½ä¸ºç©º 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; } 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; 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("", ""); 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 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}