| | |
| | | import org.dromara.common.tenant.exception.TenantException; |
| | | import org.dromara.common.tenant.helper.TenantHelper; |
| | | import org.dromara.common.web.config.properties.CaptchaProperties; |
| | | import org.dromara.system.domain.SysAuthUser; |
| | | import org.dromara.system.domain.SysUser; |
| | | import org.dromara.system.domain.bo.SocialUserBo; |
| | | import org.dromara.system.domain.bo.SysUserBo; |
| | | import org.dromara.system.domain.vo.SocialUserVo; |
| | | import org.dromara.system.domain.vo.SysTenantVo; |
| | | import org.dromara.system.domain.vo.SysUserVo; |
| | | import org.dromara.system.mapper.SocialUserMapper; |
| | | import org.dromara.system.mapper.SysUserMapper; |
| | | import org.dromara.system.service.ISocialUserService; |
| | | import org.dromara.system.service.ISysPermissionService; |
| | | import org.dromara.system.service.ISysTenantService; |
| | | import org.dromara.system.service.ISysUserService; |
| | | import org.springframework.beans.BeanUtils; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | |
| | | public class SysLoginService { |
| | | |
| | | private final SysUserMapper userMapper; |
| | | private final ISocialUserService socialUserService; |
| | | private final ISysUserService userService; |
| | | private final CaptchaProperties captchaProperties; |
| | | private final ISysPermissionService permissionService; |
| | | private final ISysTenantService tenantService; |
| | |
| | | return StpUtil.getTokenValue(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 认证授权登录 |
| | | * @param source |
| | | * @throws IOException |
| | | */ |
| | | /** |
| | | * 社交登录 |
| | | * |
| | | * @param source 登录来源 |
| | | * @param authUser 授权响应实体 |
| | | * @param request Http请求对象 |
| | | * @return 统一响应实体 |
| | | * @throws IOException |
| | | * @param authUser 授权响应实体 |
| | | * @param request Http请求对象 |
| | | * @return 统一响应实体 |
| | | */ |
| | | public R<String> socialLogin(String source, AuthResponse<AuthUser> authUser, HttpServletRequest request) throws IOException { |
| | | // 判断授权响应是否成功 |
| | | if (!authUser.ok()) { |
| | | return R.fail("对不起,授权信息验证不通过,请联系管理员"); |
| | | return R.fail("对不起,授权信息验证不通过,请退出重试!"); |
| | | } |
| | | AuthUser authUserData = authUser.getData(); |
| | | // 判断数据库中是否已存在该用户 |
| | | SysUserVo user = userMapper.selectAuthUserByUuid(source + authUserData.getUuid()); |
| | | String authId = source + authUserData.getUuid(); |
| | | |
| | | SocialUserVo user = socialUserService.selectSocialUserByAuthId(authId); |
| | | if (ObjectUtil.isNotNull(user)) { |
| | | checkTenant(user.getTenantId()); |
| | | SysUserVo dbUser = loadUserByUsername(user.getTenantId(), user.getUserName()); |
| | | // 登录 |
| | | LoginHelper.loginByDevice(buildLoginUser(dbUser), DeviceType.auth); |
| | | recordLogininfor(dbUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); |
| | | recordLoginInfo(user.getUserId()); |
| | | return R.ok(StpUtil.getTokenValue()); |
| | | //执行登录和记录登录信息操作 |
| | | return loginAndRecord(user.getTenantId(), user.getUserName(), authUserData); |
| | | } else { |
| | | // 判断是否已登录 |
| | | if (LoginHelper.getUserId() == null) { |
| | | return R.fail("授权失败,请先登录再绑定"); |
| | | } |
| | | // 组装授权用户信息 |
| | | SysAuthUser sysAuthUser = new SysAuthUser(); |
| | | sysAuthUser.setAvatar(authUserData.getAvatar()); |
| | | sysAuthUser.setUuid(source + authUserData.getUuid()); |
| | | sysAuthUser.setUserId(LoginHelper.getUserId()); |
| | | sysAuthUser.setUserName(authUserData.getUsername()); |
| | | sysAuthUser.setNickName(authUserData.getNickname()); |
| | | sysAuthUser.setEmail(authUserData.getEmail()); |
| | | sysAuthUser.setSource(source); |
| | | sysAuthUser.setCreateTime(new Date().toString()); |
| | | // 新用户,绑定第三方账号 |
| | | userMapper.insertAuthUser(sysAuthUser); |
| | | SocialUserBo socialUserBo = new SocialUserBo(); |
| | | socialUserBo.setUserId(LoginHelper.getUserId()); |
| | | socialUserBo.setAuthId(authUserData.getSource() + authUserData.getUuid()); |
| | | socialUserBo.setSource(authUserData.getSource()); |
| | | socialUserBo.setUserName(authUserData.getUsername()); |
| | | socialUserBo.setNickName(authUserData.getNickname()); |
| | | socialUserBo.setAvatar(authUserData.getAvatar()); |
| | | socialUserBo.setOpenId(authUserData.getUuid()); |
| | | BeanUtils.copyProperties(authUserData, socialUserBo); |
| | | BeanUtils.copyProperties(authUserData.getToken(), socialUserBo); |
| | | |
| | | socialUserService.insertByBo(socialUserBo); |
| | | SysUserVo lodingData = loadUserByUsername(LoginHelper.getTenantId(), LoginHelper.getUsername()); |
| | | checkTenant(lodingData.getTenantId()); |
| | | LoginHelper.loginByDevice(buildLoginUser(lodingData), DeviceType.auth); |
| | | recordLogininfor(lodingData.getTenantId(), sysAuthUser.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); |
| | | recordLoginInfo(sysAuthUser.getUserId()); |
| | | return R.ok(StpUtil.getTokenValue()); |
| | | //执行登录和记录登录信息操作 |
| | | return loginAndRecord(lodingData.getTenantId(), socialUserBo.getUserName(), authUserData); |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * 执行登录和记录登录信息操作 |
| | | * |
| | | * @param tenantId 租户ID |
| | | * @param userName 用户名 |
| | | * @param authUser 授权用户信息 |
| | | * @return 统一响应实体 |
| | | */ |
| | | private R<String> loginAndRecord(String tenantId, String userName, AuthUser authUser) { |
| | | checkTenant(tenantId); |
| | | SysUserVo dbUser = loadUserByUsername(tenantId, userName); |
| | | LoginHelper.loginByDevice(buildLoginUser(dbUser), DeviceType.SOCIAL); |
| | | recordLogininfor(dbUser.getTenantId(), userName, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")); |
| | | recordLoginInfo(dbUser.getUserId()); |
| | | return R.ok(StpUtil.getTokenValue()); |
| | | } |
| | | |
| | | /** |
| | | * 退出登录 |
| | |
| | | |
| | | private SysUserVo loadUserByUsername(String tenantId, String username) { |
| | | SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>() |
| | | .select(SysUser::getUserName, SysUser::getStatus) |
| | | .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId) |
| | | .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); |
| | |
| | | |
| | | private SysUserVo loadUserByPhonenumber(String tenantId, String phonenumber) { |
| | | SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>() |
| | | .select(SysUser::getPhonenumber, SysUser::getStatus) |
| | | .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId) |
| | | .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 SysUserVo loadUserByEmail(String tenantId, String email) { |
| | | SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>() |
| | | .select(SysUser::getPhonenumber, SysUser::getStatus) |
| | | .select(SysUser::getEmail, SysUser::getStatus) |
| | | .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId) |
| | | .eq(SysUser::getEmail, email)); |
| | | if (ObjectUtil.isNull(user)) { |
| | |
| | | String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username; |
| | | String loginFail = Constants.LOGIN_FAIL; |
| | | |
| | | // 获取用户登录错误次数(可自定义限制策略 例如: key + username + ip) |
| | | Integer errorNumber = RedisUtils.getCacheObject(errorKey); |
| | | // 获取用户登录错误次数,默认为0 (可自定义限制策略 例如: key + username + ip) |
| | | int errorNumber = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(errorKey), 0); |
| | | // 锁定时间内登录 则踢出 |
| | | if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(maxRetryCount)) { |
| | | if (errorNumber >= maxRetryCount) { |
| | | recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); |
| | | throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); |
| | | } |
| | | |
| | | if (supplier.get()) { |
| | | // 是否第一次 |
| | | errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1; |
| | | // 错误次数递增 |
| | | errorNumber++; |
| | | RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime)); |
| | | // 达到规定错误次数 则锁定登录 |
| | | if (errorNumber.equals(maxRetryCount)) { |
| | | RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime)); |
| | | if (errorNumber >= maxRetryCount) { |
| | | recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); |
| | | throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); |
| | | } else { |
| | | // 未达到规定错误次数 则递增 |
| | | RedisUtils.setCacheObject(errorKey, errorNumber); |
| | | // 未达到规定错误次数 |
| | | recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber)); |
| | | throw new UserException(loginType.getRetryLimitCount(), errorNumber); |
| | | } |
| | |
| | | log.info("登录租户:{} 已被停用.", tenantId); |
| | | throw new TenantException("tenant.blocked"); |
| | | } else if (ObjectUtil.isNotNull(tenant.getExpireTime()) |
| | | && new Date().after(tenant.getExpireTime())) { |
| | | && new Date().after(tenant.getExpireTime())) { |
| | | log.info("登录租户:{} 已超过有效期.", tenantId); |
| | | throw new TenantException("tenant.expired"); |
| | | } |