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 å°ç¨åºcode * @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() { 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=å°ç¨åºcodeä¸è½ä¸ºç©º 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ï¼please 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 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=å°ç¨åºcodeä¸è½ä¸ºç©º 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; } 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; } 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 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 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 æ¤å¤ä½¿ç¨ææºå·æ¥è¯¢rediséªè¯ç ä¸åæ°éªè¯ç æ¯å¦ä¸è´ ç¨æ·èªè¡å®ç° 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; } /** * æå»ºç»å½ç¨æ· */ 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 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}