ÎļþÃû´Ó ruoyi-modules/ruoyi-system/src/main/java/com/ruoyi/system/service/SysLoginService.java ÐÞ¸Ä |
| | |
| | | package com.ruoyi.system.service; |
| | | package com.ruoyi.web.service; |
| | | |
| | | import cn.dev33.satoken.exception.NotLoginException; |
| | | import cn.dev33.satoken.secure.BCrypt; |
| | |
| | | import cn.hutool.core.bean.BeanUtil; |
| | | import cn.hutool.core.util.ObjectUtil; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.ruoyi.common.core.constant.CacheConstants; |
| | | import com.ruoyi.common.core.constant.Constants; |
| | | import com.ruoyi.common.core.constant.GlobalConstants; |
| | | import com.ruoyi.common.core.domain.dto.RoleDTO; |
| | | import com.ruoyi.common.core.domain.model.LoginUser; |
| | | import com.ruoyi.common.core.domain.model.XcxLoginUser; |
| | | import com.ruoyi.common.core.enums.DeviceType; |
| | | import com.ruoyi.common.core.enums.LoginType; |
| | | import com.ruoyi.common.core.enums.TenantStatus; |
| | | import com.ruoyi.common.core.enums.UserStatus; |
| | | import com.ruoyi.common.core.exception.user.CaptchaException; |
| | | import com.ruoyi.common.core.exception.user.CaptchaExpireException; |
| | |
| | | import com.ruoyi.common.log.event.LogininforEvent; |
| | | import com.ruoyi.common.redis.utils.RedisUtils; |
| | | import com.ruoyi.common.satoken.utils.LoginHelper; |
| | | import com.ruoyi.common.tenant.exception.TenantException; |
| | | import com.ruoyi.common.tenant.helper.TenantHelper; |
| | | import com.ruoyi.common.web.config.properties.CaptchaProperties; |
| | | import com.ruoyi.system.domain.SysUser; |
| | | import com.ruoyi.system.domain.vo.SysTenantVo; |
| | | import com.ruoyi.system.domain.vo.SysUserVo; |
| | | import com.ruoyi.system.mapper.SysUserMapper; |
| | | import com.ruoyi.system.service.ISysPermissionService; |
| | | import com.ruoyi.system.service.ISysTenantService; |
| | | import jakarta.servlet.http.HttpServletRequest; |
| | | import lombok.RequiredArgsConstructor; |
| | | import lombok.extern.slf4j.Slf4j; |
| | |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import java.time.Duration; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | import java.util.function.Supplier; |
| | | |
| | |
| | | public class SysLoginService { |
| | | |
| | | private final SysUserMapper userMapper; |
| | | private final ISysConfigService configService; |
| | | private final SysPermissionService permissionService; |
| | | private final CaptchaProperties captchaProperties; |
| | | private final ISysPermissionService permissionService; |
| | | private final ISysTenantService tenantService; |
| | | |
| | | @Value("${user.password.maxRetryCount}") |
| | | private Integer maxRetryCount; |
| | |
| | | * @param uuid å¯ä¸æ è¯ |
| | | * @return ç»æ |
| | | */ |
| | | public String login(String username, String password, String code, String uuid) { |
| | | public String login(String tenantId, String username, String password, String code, String uuid) { |
| | | HttpServletRequest request = ServletUtils.getRequest(); |
| | | boolean captchaEnabled = configService.selectCaptchaEnabled(); |
| | | boolean captchaEnabled = captchaProperties.getEnable(); |
| | | // éªè¯ç å¼å
³ |
| | | if (captchaEnabled) { |
| | | validateCaptcha(username, code, uuid, request); |
| | | validateCaptcha(tenantId, username, code, uuid, request); |
| | | } |
| | | SysUserVo user = loadUserByUsername(username); |
| | | checkLogin(LoginType.PASSWORD, username, () -> !BCrypt.checkpw(password, user.getPassword())); |
| | | // æ ¡éªç§æ· |
| | | checkTenant(tenantId); |
| | | |
| | | SysUserVo user = loadUserByUsername(tenantId, username); |
| | | checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword())); |
| | | // æ¤å¤å¯æ ¹æ®ç»å½ç¨æ·çæ°æ®ä¸å èªè¡å建 loginUser |
| | | LoginUser loginUser = buildLoginUser(user); |
| | | // çætoken |
| | | LoginHelper.loginByDevice(loginUser, DeviceType.PC); |
| | | |
| | | recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); |
| | | recordLogininfor(loginUser.getTenantId(), username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); |
| | | recordLoginInfo(user.getUserId()); |
| | | return StpUtil.getTokenValue(); |
| | | } |
| | | |
| | | public String smsLogin(String phonenumber, String smsCode) { |
| | | public String smsLogin(String tenantId, String phonenumber, String smsCode) { |
| | | // æ ¡éªç§æ· |
| | | checkTenant(tenantId); |
| | | // éè¿ææºå·æ¥æ¾ç¨æ· |
| | | SysUserVo user = loadUserByPhonenumber(phonenumber); |
| | | SysUserVo user = loadUserByPhonenumber(tenantId, phonenumber); |
| | | |
| | | checkLogin(LoginType.SMS, user.getUserName(), () -> !validateSmsCode(phonenumber, smsCode)); |
| | | checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode)); |
| | | // æ¤å¤å¯æ ¹æ®ç»å½ç¨æ·çæ°æ®ä¸å èªè¡å建 loginUser |
| | | LoginUser loginUser = buildLoginUser(user); |
| | | // çætoken |
| | | LoginHelper.loginByDevice(loginUser, DeviceType.APP); |
| | | |
| | | recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); |
| | | recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); |
| | | recordLoginInfo(user.getUserId()); |
| | | return StpUtil.getTokenValue(); |
| | | } |
| | |
| | | // æ ¡éª appid + appsrcret + xcxCode è°ç¨ç»å½åè¯æ ¡éªæ¥å£ è·å session_key ä¸ openid |
| | | String openid = ""; |
| | | SysUserVo user = loadUserByOpenid(openid); |
| | | // æ ¡éªç§æ· |
| | | checkTenant(user.getTenantId()); |
| | | |
| | | // æ¤å¤å¯æ ¹æ®ç»å½ç¨æ·çæ°æ®ä¸å èªè¡å建 loginUser |
| | | XcxLoginUser loginUser = new XcxLoginUser(); |
| | | loginUser.setTenantId(user.getTenantId()); |
| | | loginUser.setUserId(user.getUserId()); |
| | | loginUser.setUsername(user.getUserName()); |
| | | loginUser.setUserType(user.getUserType()); |
| | |
| | | // çætoken |
| | | LoginHelper.loginByDevice(loginUser, DeviceType.XCX); |
| | | |
| | | recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); |
| | | recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); |
| | | recordLoginInfo(user.getUserId()); |
| | | return StpUtil.getTokenValue(); |
| | | } |
| | |
| | | try { |
| | | LoginUser loginUser = LoginHelper.getLoginUser(); |
| | | StpUtil.logout(); |
| | | recordLogininfor(loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success")); |
| | | recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success")); |
| | | } catch (NotLoginException ignored) { |
| | | } |
| | | } |
| | |
| | | /** |
| | | * è®°å½ç»å½ä¿¡æ¯ |
| | | * |
| | | * @param tenantId ç§æ·ID |
| | | * @param username ç¨æ·å |
| | | * @param status ç¶æ |
| | | * @param message æ¶æ¯å
容 |
| | | * @return |
| | | */ |
| | | private void recordLogininfor(String username, String status, String message) { |
| | | private void recordLogininfor(String tenantId, String username, String status, String message) { |
| | | LogininforEvent logininforEvent = new LogininforEvent(); |
| | | logininforEvent.setTenantId(tenantId); |
| | | logininforEvent.setUsername(username); |
| | | logininforEvent.setStatus(status); |
| | | logininforEvent.setMessage(message); |
| | |
| | | /** |
| | | * æ ¡éªçä¿¡éªè¯ç |
| | | */ |
| | | private boolean validateSmsCode(String phonenumber, String smsCode) { |
| | | String code = RedisUtils.getCacheObject(CacheConstants.CAPTCHA_CODE_KEY + phonenumber); |
| | | private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) { |
| | | String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber); |
| | | if (StringUtils.isBlank(code)) { |
| | | recordLogininfor(phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); |
| | | recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); |
| | | throw new CaptchaExpireException(); |
| | | } |
| | | return code.equals(smsCode); |
| | |
| | | * @param code éªè¯ç |
| | | * @param uuid å¯ä¸æ è¯ |
| | | */ |
| | | public void validateCaptcha(String username, String code, String uuid, HttpServletRequest request) { |
| | | String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, ""); |
| | | public void validateCaptcha(String tenantId, String username, String code, String uuid, HttpServletRequest request) { |
| | | String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, ""); |
| | | String captcha = RedisUtils.getCacheObject(verifyKey); |
| | | RedisUtils.deleteObject(verifyKey); |
| | | if (captcha == null) { |
| | | recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); |
| | | recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); |
| | | throw new CaptchaExpireException(); |
| | | } |
| | | if (!code.equalsIgnoreCase(captcha)) { |
| | | recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); |
| | | recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); |
| | | throw new CaptchaException(); |
| | | } |
| | | } |
| | | |
| | | private SysUserVo loadUserByUsername(String username) { |
| | | private SysUserVo loadUserByUsername(String tenantId, String username) { |
| | | SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>() |
| | | .select(SysUser::getUserName, SysUser::getStatus) |
| | | .eq(SysUser::getUserName, username)); |
| | | .select(SysUser::getUserName, SysUser::getStatus) |
| | | .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId) |
| | | .eq(SysUser::getUserName, username)); |
| | | if (ObjectUtil.isNull(user)) { |
| | | log.info("ç»å½ç¨æ·ï¼{} ä¸åå¨.", username); |
| | | throw new UserException("user.not.exists", username); |
| | |
| | | return userMapper.selectUserByUserName(username); |
| | | } |
| | | |
| | | private SysUserVo loadUserByPhonenumber(String phonenumber) { |
| | | private SysUserVo loadUserByPhonenumber(String tenantId, String phonenumber) { |
| | | SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>() |
| | | .select(SysUser::getPhonenumber, SysUser::getStatus) |
| | | .eq(SysUser::getPhonenumber, phonenumber)); |
| | | .select(SysUser::getPhonenumber, SysUser::getStatus) |
| | | .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId) |
| | | .eq(SysUser::getPhonenumber, phonenumber)); |
| | | if (ObjectUtil.isNull(user)) { |
| | | log.info("ç»å½ç¨æ·ï¼{} ä¸åå¨.", phonenumber); |
| | | throw new UserException("user.not.exists", phonenumber); |
| | |
| | | */ |
| | | private LoginUser buildLoginUser(SysUserVo user) { |
| | | LoginUser loginUser = new LoginUser(); |
| | | loginUser.setTenantId(user.getTenantId()); |
| | | loginUser.setUserId(user.getUserId()); |
| | | loginUser.setDeptId(user.getDeptId()); |
| | | loginUser.setUsername(user.getUserName()); |
| | | loginUser.setUserType(user.getUserType()); |
| | | loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId(), user.isAdmin())); |
| | | loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId(), user.isAdmin())); |
| | | loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId())); |
| | | loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId())); |
| | | loginUser.setDeptName(ObjectUtil.isNull(user.getDept()) ? "" : user.getDept().getDeptName()); |
| | | List<RoleDTO> roles = BeanUtil.copyToList(user.getRoles(), RoleDTO.class); |
| | | loginUser.setRoles(roles); |
| | |
| | | /** |
| | | * ç»å½æ ¡éª |
| | | */ |
| | | private void checkLogin(LoginType loginType, String username, Supplier<Boolean> supplier) { |
| | | String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username; |
| | | private void checkLogin(LoginType loginType, String tenantId, String username, Supplier<Boolean> supplier) { |
| | | String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username; |
| | | String loginFail = Constants.LOGIN_FAIL; |
| | | |
| | | // è·åç¨æ·ç»å½é误次æ°(å¯èªå®ä¹éå¶çç¥ ä¾å¦: key + username + ip) |
| | | Integer errorNumber = RedisUtils.getCacheObject(errorKey); |
| | | // é宿¶é´å
ç»å½ åè¸¢åº |
| | | if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(maxRetryCount)) { |
| | | recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); |
| | | recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); |
| | | throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); |
| | | } |
| | | |
| | |
| | | // è¾¾å°è§å®éè¯¯æ¬¡æ° åéå®ç»å½ |
| | | if (errorNumber.equals(maxRetryCount)) { |
| | | RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime)); |
| | | recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); |
| | | recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); |
| | | throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); |
| | | } else { |
| | | // æªè¾¾å°è§å®éè¯¯æ¬¡æ° åéå¢ |
| | | RedisUtils.setCacheObject(errorKey, errorNumber); |
| | | recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber)); |
| | | recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber)); |
| | | throw new UserException(loginType.getRetryLimitCount(), errorNumber); |
| | | } |
| | | } |
| | |
| | | // ç»å½æå æ¸
空éè¯¯æ¬¡æ° |
| | | RedisUtils.deleteObject(errorKey); |
| | | } |
| | | |
| | | private void checkTenant(String tenantId) { |
| | | if (!TenantHelper.isEnable()) { |
| | | return; |
| | | } |
| | | SysTenantVo tenant = tenantService.queryByTenantId(tenantId); |
| | | if (ObjectUtil.isNull(tenant)) { |
| | | log.info("ç»å½ç§æ·ï¼{} ä¸åå¨.", tenantId); |
| | | throw new TenantException("tenant.not.exists"); |
| | | } else if (TenantStatus.DISABLE.getCode().equals(tenant.getStatus())) { |
| | | log.info("ç»å½ç§æ·ï¼{} 已被åç¨.", tenantId); |
| | | throw new TenantException("tenant.blocked"); |
| | | } else if (ObjectUtil.isNotNull(tenant.getExpireTime()) |
| | | && new Date().after(tenant.getExpireTime())) { |
| | | log.info("ç»å½ç§æ·ï¼{} å·²è¶
è¿æææ.", tenantId); |
| | | throw new TenantException("tenant.expired"); |
| | | } |
| | | } |
| | | |
| | | } |