From 4a353896e3ab74e6bd9acda6bebc2fde167f2d00 Mon Sep 17 00:00:00 2001 From: 疯狂的狮子Li <15040126243@163.com> Date: 星期三, 23 三月 2022 00:33:28 +0800 Subject: [PATCH] add 增加 短信登录 与 小程序登录 示例 --- ruoyi-admin/src/main/resources/i18n/messages_en_US.properties | 5 + ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java | 104 ++++++++++++++++++++++++++ ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java | 11 ++ ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java | 34 ++++++++ ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml | 5 + ruoyi-admin/src/main/resources/i18n/messages.properties | 5 + ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java | 8 ++ ruoyi-common/src/main/java/com/ruoyi/common/enums/DeviceType.java | 7 + ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java | 8 ++ ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/SmsLoginBody.java | 33 ++++++++ ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties | 5 + 11 files changed, 224 insertions(+), 1 deletions(-) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java index fad8b5b..37f7e99 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java @@ -7,6 +7,7 @@ import com.ruoyi.common.core.domain.entity.SysMenu; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.model.LoginBody; +import com.ruoyi.common.core.domain.model.SmsLoginBody; import com.ruoyi.common.helper.LoginHelper; import com.ruoyi.system.domain.vo.RouterVo; import com.ruoyi.system.service.ISysMenuService; @@ -22,6 +23,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import javax.validation.constraints.NotBlank; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -60,6 +62,38 @@ return R.ok(ajax); } + /** + * 鐭俊鐧诲綍(绀轰緥) + * + * @param smsLoginBody 鐧诲綍淇℃伅 + * @return 缁撴灉 + */ + @ApiOperation("鐭俊鐧诲綍(绀轰緥)") + @PostMapping("/smsLogin") + public R<Map<String, Object>> smsLogin(@Validated @RequestBody SmsLoginBody smsLoginBody) { + Map<String, Object> ajax = new HashMap<>(); + // 鐢熸垚浠ょ墝 + String token = loginService.smsLogin(smsLoginBody.getPhonenumber(), smsLoginBody.getSmsCode()); + ajax.put(Constants.TOKEN, token); + return R.ok(ajax); + } + + /** + * 灏忕▼搴忕櫥褰�(绀轰緥) + * + * @param xcxCode 灏忕▼搴廲ode + * @return 缁撴灉 + */ + @ApiOperation("鐭俊鐧诲綍(绀轰緥)") + @PostMapping("/xcxLogin") + public R<Map<String, Object>> xcxLogin(@NotBlank(message = "{xcx.code.not.blank}") String xcxCode) { + Map<String, Object> ajax = new HashMap<>(); + // 鐢熸垚浠ょ墝 + String token = loginService.xcxLogin(xcxCode); + ajax.put(Constants.TOKEN, token); + return R.ok(ajax); + } + @ApiOperation("鐧诲嚭鏂规硶") @PostMapping("/logout") public R<Void> logout() { diff --git a/ruoyi-admin/src/main/resources/i18n/messages.properties b/ruoyi-admin/src/main/resources/i18n/messages.properties index 522d1bc..ac1d8c2 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.phonenumber.not.blank=鐢ㄦ埛鎵嬫満鍙蜂笉鑳戒负绌� user.mobile.phone.number.not.valid=鎵嬫満鍙锋牸寮忛敊璇� user.login.success=鐧诲綍鎴愬姛 user.register.success=娉ㄥ唽鎴愬姛 @@ -38,3 +39,7 @@ no.view.permission=鎮ㄦ病鏈夋煡鐪嬫暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}] repeat.submit.message=涓嶅厑璁搁噸澶嶆彁浜わ紝璇风◢鍊欏啀璇� rate.limiter.message=璁块棶杩囦簬棰戠箒锛岃绋嶅�欏啀璇� +sms.code.not.blank=鐭俊楠岃瘉鐮佷笉鑳戒负绌� +sms.code.retry.limit.count=鐭俊楠岃瘉鐮佽緭鍏ラ敊璇瘂0}娆� +sms.code.retry.limit.exceed=鐭俊楠岃瘉鐮侀敊璇鏁拌繃澶氾紝甯愭埛閿佸畾{0}鍒嗛挓 +xcx.code.not.blank=灏忕▼搴廲ode涓嶈兘涓虹┖ 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 5dbdac5..9076f79 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.phonenumber.not.blank=Phone number cannot be blank user.mobile.phone.number.not.valid=Phone number format error user.login.success=Login successful user.register.success=Register successful @@ -38,3 +39,7 @@ no.view.permission=You do not have permission to view data锛宲lease contact your administrator to add permissions [{0}] repeat.submit.message=Repeat submit is not allowed, please try again later 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=Too many sms code errors, account locked for {0} minutes +xcx.code.not.blank=Mini program code 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 522d1bc..ac1d8c2 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.phonenumber.not.blank=鐢ㄦ埛鎵嬫満鍙蜂笉鑳戒负绌� user.mobile.phone.number.not.valid=鎵嬫満鍙锋牸寮忛敊璇� user.login.success=鐧诲綍鎴愬姛 user.register.success=娉ㄥ唽鎴愬姛 @@ -38,3 +39,7 @@ no.view.permission=鎮ㄦ病鏈夋煡鐪嬫暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}] repeat.submit.message=涓嶅厑璁搁噸澶嶆彁浜わ紝璇风◢鍊欏啀璇� rate.limiter.message=璁块棶杩囦簬棰戠箒锛岃绋嶅�欏啀璇� +sms.code.not.blank=鐭俊楠岃瘉鐮佷笉鑳戒负绌� +sms.code.retry.limit.count=鐭俊楠岃瘉鐮佽緭鍏ラ敊璇瘂0}娆� +sms.code.retry.limit.exceed=鐭俊楠岃瘉鐮侀敊璇鏁拌繃澶氾紝甯愭埛閿佸畾{0}鍒嗛挓 +xcx.code.not.blank=灏忕▼搴廲ode涓嶈兘涓虹┖ diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/SmsLoginBody.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/SmsLoginBody.java new file mode 100644 index 0000000..f3ef445 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/SmsLoginBody.java @@ -0,0 +1,33 @@ +package com.ruoyi.common.core.domain.model; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * 鐭俊鐧诲綍瀵硅薄 + * + * @author Lion Li + */ + +@Data +@ApiModel("鐭俊鐧诲綍瀵硅薄") +public class SmsLoginBody { + + /** + * 鐢ㄦ埛鍚� + */ + @NotBlank(message = "{user.phonenumber.not.blank}") + @ApiModelProperty(value = "鐢ㄦ埛鎵嬫満鍙�") + private String phonenumber; + + /** + * 鐢ㄦ埛瀵嗙爜 + */ + @NotBlank(message = "{sms.code.not.blank}") + @ApiModelProperty(value = "鐭俊楠岃瘉鐮�") + private String smsCode; + +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/DeviceType.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/DeviceType.java index e6ac849..118a212 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/DeviceType.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/DeviceType.java @@ -21,7 +21,12 @@ /** * app绔� */ - APP("app"); + APP("app"), + + /** + * 灏忕▼搴忕 + */ + XCX("xcx"); private final String device; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java index 46e48fe..9b585e1 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java @@ -69,6 +69,14 @@ SysUser selectUserByUserName(String userName); /** + * 閫氳繃鎵嬫満鍙锋煡璇㈢敤鎴� + * + * @param phonenumber 鎵嬫満鍙� + * @return 鐢ㄦ埛瀵硅薄淇℃伅 + */ + SysUser selectUserByPhonenumber(String phonenumber); + + /** * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛 * * @param userId 鐢ㄦ埛ID diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java index 741ae4b..9ecd86e 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java @@ -49,6 +49,14 @@ SysUser selectUserByUserName(String userName); /** + * 閫氳繃鎵嬫満鍙锋煡璇㈢敤鎴� + * + * @param phonenumber 鎵嬫満鍙� + * @return 鐢ㄦ埛瀵硅薄淇℃伅 + */ + SysUser selectUserByPhonenumber(String phonenumber); + + /** * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛 * * @param userId 鐢ㄦ埛ID diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java index 62ca18b..be5aac2 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java @@ -87,6 +87,8 @@ // 鐧诲綍鎴愬姛 娓呯┖閿欒娆℃暟 RedisUtils.deleteObject(Constants.LOGIN_ERROR + username); + + // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser LoginUser loginUser = buildLoginUser(user); // 鐢熸垚token LoginHelper.loginByDevice(loginUser, DeviceType.PC); @@ -96,8 +98,78 @@ return StpUtil.getTokenValue(); } + public String smsLogin(String phonenumber, String smsCode) { + // 閫氳繃鎵嬫満鍙锋煡鎵剧敤鎴� + SysUser user = loadUserByPhonenumber(phonenumber); + + HttpServletRequest request = ServletUtils.getRequest(); + // 鑾峰彇鐢ㄦ埛鐧诲綍閿欒娆℃暟(鍙嚜瀹氫箟闄愬埗绛栫暐 渚嬪: key + username + ip) + Integer errorNumber = RedisUtils.getCacheObject(Constants.LOGIN_ERROR + user.getUserName()); + // 閿佸畾鏃堕棿鍐呯櫥褰� 鍒欒涪鍑� + if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(Constants.LOGIN_ERROR_NUMBER)) { + asyncService.recordLogininfor(user.getUserName(), Constants.LOGIN_FAIL, MessageUtils.message("sms.code.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME), request); + throw new UserException("sms.code.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME); + } + + if (!validateSmsCode(phonenumber, smsCode)) { + // 鏄惁绗竴娆� + errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1; + // 杈惧埌瑙勫畾閿欒娆℃暟 鍒欓攣瀹氱櫥褰� + if (errorNumber.equals(Constants.LOGIN_ERROR_NUMBER)) { + RedisUtils.setCacheObject(Constants.LOGIN_ERROR + user.getUserName(), errorNumber, Constants.LOGIN_ERROR_LIMIT_TIME, TimeUnit.MINUTES); + asyncService.recordLogininfor(user.getUserName(), Constants.LOGIN_FAIL, MessageUtils.message("sms.code.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME), request); + throw new UserException("sms.code.retry.limit.exceed", Constants.LOGIN_ERROR_LIMIT_TIME); + } else { + // 鏈揪鍒拌瀹氶敊璇鏁� 鍒欓�掑 + RedisUtils.setCacheObject(Constants.LOGIN_ERROR + user.getUserName(), errorNumber); + asyncService.recordLogininfor(user.getUserName(), Constants.LOGIN_FAIL, MessageUtils.message("sms.code.retry.limit.count", errorNumber), request); + throw new UserException("sms.code.retry.limit.count", errorNumber); + } + } + + // 鐧诲綍鎴愬姛 娓呯┖閿欒娆℃暟 + RedisUtils.deleteObject(Constants.LOGIN_ERROR + user.getUserName()); + + // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser + LoginUser loginUser = buildLoginUser(user); + // 鐢熸垚token + LoginHelper.loginByDevice(loginUser, DeviceType.APP); + + asyncService.recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"), request); + recordLoginInfo(user.getUserId(), user.getUserName()); + return StpUtil.getTokenValue(); + } + + + public String xcxLogin(String xcxCode) { + HttpServletRequest request = ServletUtils.getRequest(); + // xcxCode 涓� 灏忕▼搴忚皟鐢� wx.login 鎺堟潈鍚庤幏鍙� + // todo 浠ヤ笅鑷瀹炵幇 + // 鏍¢獙 appid + appsrcret + xcxCode 璋冪敤鐧诲綍鍑瘉鏍¢獙鎺ュ彛 鑾峰彇 session_key 涓� openid + String openid = ""; + SysUser user = loadUserByOpenid(openid); + + // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser + LoginUser loginUser = buildLoginUser(user); + // 鐢熸垚token + LoginHelper.loginByDevice(loginUser, DeviceType.XCX); + + asyncService.recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"), request); + recordLoginInfo(user.getUserId(), user.getUserName()); + return StpUtil.getTokenValue(); + } + + public void logout(String loginName) { asyncService.recordLogininfor(loginName, Constants.LOGOUT, MessageUtils.message("user.logout.success"), ServletUtils.getRequest()); + } + + /** + * 鏍¢獙鐭俊楠岃瘉鐮� + */ + private boolean validateSmsCode(String phonenumber, String smsCode) { + // todo 姝ゅ浣跨敤鎵嬫満鍙锋煡璇edis楠岃瘉鐮佷笌鍙傛暟楠岃瘉鐮佹槸鍚︿竴鑷� 鐢ㄦ埛鑷瀹炵幇 + return true; } /** @@ -136,6 +208,38 @@ return user; } + private SysUser loadUserByPhonenumber(String phonenumber) { + SysUser user = userService.selectUserByPhonenumber(phonenumber); + if (ObjectUtil.isNull(user)) { + log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", phonenumber); + throw new UserException("user.not.exists", phonenumber); + } else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) { + log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍒犻櫎.", phonenumber); + throw new UserException("user.password.delete", phonenumber); + } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { + log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", phonenumber); + throw new UserException("user.blocked", phonenumber); + } + return user; + } + + private SysUser loadUserByOpenid(String openid) { + // 浣跨敤 openid 鏌ヨ缁戝畾鐢ㄦ埛 濡傛湭缁戝畾鐢ㄦ埛 鍒欐牴鎹笟鍔¤嚜琛屽鐞� 渚嬪 鍒涘缓榛樿鐢ㄦ埛 + // todo 鑷瀹炵幇 userService.selectUserByOpenid(openid); + SysUser user = new SysUser(); + if (ObjectUtil.isNull(user)) { + log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", openid); + // todo 鐢ㄦ埛涓嶅瓨鍦� 涓氬姟閫昏緫鑷瀹炵幇 + } else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) { + log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍒犻櫎.", openid); + // todo 鐢ㄦ埛宸茶鍒犻櫎 涓氬姟閫昏緫鑷瀹炵幇 + } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) { + log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", openid); + // todo 鐢ㄦ埛宸茶鍋滅敤 涓氬姟閫昏緫鑷瀹炵幇 + } + return user; + } + /** * 鏋勫缓鐧诲綍鐢ㄦ埛 */ diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java index 09c5ba2..11ff7b9 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java @@ -138,6 +138,17 @@ } /** + * 閫氳繃鎵嬫満鍙锋煡璇㈢敤鎴� + * + * @param phonenumber 鎵嬫満鍙� + * @return 鐢ㄦ埛瀵硅薄淇℃伅 + */ + @Override + public SysUser selectUserByPhonenumber(String phonenumber) { + return baseMapper.selectUserByPhonenumber(phonenumber); + } + + /** * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛 * * @param userId 鐢ㄦ埛ID diff --git a/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml index 3117788..d4fd23f 100644 --- a/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml @@ -121,6 +121,11 @@ where u.del_flag = '0' and u.user_name = #{userName} </select> + <select id="selectUserByPhonenumber" parameterType="String" resultMap="SysUserResult"> + <include refid="selectUserVo"/> + where u.del_flag = '0' and u.phonenumber = #{phonenumber} + </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