/* * Copyright (c) 2018-2028, Chill Zhuang All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * Neither the name of the dreamlu.net developer nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * Author: Chill 庄骞 (smallchill@163.com) */ package com.vci.ubcs.system.user.service.impl; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.vci.ubcs.system.cache.DictCache; import com.vci.ubcs.system.cache.ParamCache; import com.vci.ubcs.system.cache.SysCache; import com.vci.ubcs.system.entity.Strategy; import com.vci.ubcs.system.entity.Tenant; import com.vci.ubcs.system.enums.DictEnum; import com.vci.ubcs.system.feign.ISysClient; import com.vci.ubcs.common.constant.CommonConstant; import com.vci.ubcs.system.user.cache.UserCache; import com.vci.ubcs.system.user.entity.*; import com.vci.ubcs.system.user.enums.UserEnum; import com.vci.ubcs.system.user.excel.UserExcel; import com.vci.ubcs.system.user.mapper.UserMapper; import com.vci.ubcs.system.user.service.IUserDeptService; import com.vci.ubcs.system.user.service.IUserOauthService; import com.vci.ubcs.system.user.service.IUserService; import com.vci.ubcs.system.user.vo.UserVO; import com.vci.ubcs.system.user.wrapper.UserWrapper; import lombok.RequiredArgsConstructor; import org.springblade.core.log.exception.ServiceException; import org.springblade.core.mp.base.BaseServiceImpl; import org.springblade.core.mp.support.Condition; import org.springblade.core.mp.support.Query; import org.springblade.core.secure.utils.AuthUtil; import org.springblade.core.tenant.BladeTenantProperties; import org.springblade.core.tool.api.R; import org.springblade.core.tool.constant.BladeConstant; import org.springblade.core.tool.support.Kv; import org.springblade.core.tool.utils.*; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.DigestUtils; import java.util.*; import static com.vci.ubcs.common.constant.CommonConstant.DEFAULT_PARAM_PASSWORD; /** * 服务实现类 * * @author Chill */ @Service @RequiredArgsConstructor public class UserServiceImpl extends BaseServiceImpl implements IUserService { private static final String GUEST_NAME = "guest"; private final IUserDeptService userDeptService; private final IUserOauthService userOauthService; private final ISysClient sysClient; private final BladeTenantProperties tenantProperties; //拿到配置的超管id @Value("${user-info.id}") private String adminUserId; @Override @Transactional(rollbackFor = Exception.class) public boolean submit(User user) { if (StringUtil.isBlank(user.getTenantId())) { user.setTenantId(BladeConstant.ADMIN_TENANT_ID); } String tenantId = user.getTenantId(); //Tenant tenant = SysCache.getTenant(tenantId); if (Func.isNotEmpty(user.getPassword())) { user.setPassword(DigestUtil.encrypt(user.getPassword())); } Long userCount = baseMapper.selectCount(Wrappers.query().lambda().eq(User::getTenantId, tenantId).eq(User::getAccount, user.getAccount())); if (userCount > 0L && Func.isEmpty(user.getId())) { throw new ServiceException(StringUtil.format("当前用户 [{}] 已存在!", user.getAccount())); } return save(user) && submitUserDept(user); } @Override @Transactional(rollbackFor = Exception.class) public boolean submitList(List users) { Boolean flag = true; for (User user : users){ if (StringUtil.isBlank(user.getTenantId())) { user.setTenantId(BladeConstant.ADMIN_TENANT_ID); } String tenantId = user.getTenantId(); if (Func.isNotEmpty(user.getPassword())) { user.setPassword(DigestUtil.encrypt(user.getPassword())); } Long userCount = baseMapper.selectCount(Wrappers.query().lambda().eq(User::getTenantId, tenantId).eq(User::getAccount, user.getAccount())); if (userCount > 0L && Func.isEmpty(user.getId())) { throw new ServiceException(StringUtil.format("当前用户 [{}] 已存在!", user.getAccount())); } flag = save(user) && submitUserDept(user); } return flag; } @Override @Transactional(rollbackFor = Exception.class) public boolean updateUser(User user) { String tenantId = user.getTenantId(); Long userCount = baseMapper.selectCount( Wrappers.query().lambda() .eq(User::getTenantId, tenantId) .eq(User::getAccount, user.getAccount()) .notIn(User::getId, user.getId()) ); if (userCount > 0L) { throw new ServiceException(StringUtil.format("当前用户 [{}] 已存在!", user.getAccount())); } return updateUserInfo(user) && submitUserDept(user); } @Override public boolean updateUserInfo(User user) { user.setPassword(null); return updateById(user); } private boolean submitUserDept(User user) { List deptIdList = Func.toLongList(user.getDeptId()); List userDeptList = new ArrayList<>(); deptIdList.forEach(deptId -> { UserDept userDept = new UserDept(); userDept.setUserId(user.getId()); userDept.setDeptId(deptId); userDeptList.add(userDept); }); userDeptService.remove(Wrappers.update().lambda().eq(UserDept::getUserId, user.getId())); return userDeptService.saveBatch(userDeptList); } @Override public IPage selectUserPage(IPage page, User user, Long deptId, String tenantId) { List deptIdList = SysCache.getDeptChildIds(deptId); return page.setRecords(baseMapper.selectUserPage(page, user, deptIdList, tenantId)); } @Override public IPage selectUserSearch(UserVO user, Query query) { LambdaQueryWrapper queryWrapper = Wrappers.query().lambda(); String tenantId = AuthUtil.getTenantId(); if (StringUtil.isNotBlank(tenantId)) { queryWrapper.eq(User::getTenantId, tenantId); } if (StringUtil.isNotBlank(user.getName())) { queryWrapper.like(User::getName, user.getName()); } if (StringUtil.isNotBlank(user.getDeptName())) { String deptIds = SysCache.getDeptIdsByFuzzy(AuthUtil.getTenantId(), user.getDeptName()); if (StringUtil.isNotBlank(deptIds)) { queryWrapper.and(wrapper -> { List ids = Func.toStrList(deptIds); ids.forEach(id -> wrapper.like(User::getDeptId, id).or()); }); } } if (StringUtil.isNotBlank(user.getPostName())) { String postIds = SysCache.getPostIdsByFuzzy(AuthUtil.getTenantId(), user.getPostName()); if (StringUtil.isNotBlank(postIds)) { queryWrapper.and(wrapper -> { List ids = Func.toStrList(postIds); ids.forEach(id -> wrapper.like(User::getPostId, id).or()); }); } } IPage pages = this.page(Condition.getPage(query), queryWrapper); return UserWrapper.build().pageVO(pages); } @Override public User userByAccount(String tenantId, String account) { return baseMapper.selectOne(Wrappers.query().lambda().eq(User::getTenantId, tenantId).eq(User::getAccount, account).eq(User::getIsDeleted, BladeConstant.DB_NOT_DELETED)); } @Override public UserInfo userInfo(Long userId) { User user = baseMapper.selectById(userId); return buildUserInfo(user); } @Override public UserInfo userInfo(String tenantId, String account) { User user = baseMapper.getUser(tenantId, account); return buildUserInfo(user); } @Override public UserInfo userInfo(String tenantId, String account, UserEnum userEnum) { User user = baseMapper.getUser(tenantId, account); return buildUserInfo(user, userEnum); } private UserInfo buildUserInfo(User user) { return buildUserInfo(user, UserEnum.WEB); } private UserInfo buildUserInfo(User user, UserEnum userEnum) { if (ObjectUtil.isEmpty(user)) { return null; } UserInfo userInfo = new UserInfo(); userInfo.setUser(user); if (Func.isNotEmpty(user)) { R> result = sysClient.getRoleAliases(user.getRoleId()); if (result.isSuccess()) { List roleAlias = result.getData(); userInfo.setRoles(roleAlias); } } // 根据每个用户平台,建立对应的detail表,通过查询将结果集写入到detail字段 Kv detail = Kv.create().set("type", userEnum.getName()); if (userEnum == UserEnum.WEB) { UserWeb userWeb = new UserWeb(); UserWeb query = userWeb.selectOne(Wrappers.lambdaQuery().eq(UserWeb::getUserId, user.getId())); if (ObjectUtil.isNotEmpty(query)) { detail.set("ext", query.getUserExt()); } } else if (userEnum == UserEnum.APP) { UserApp userApp = new UserApp(); UserApp query = userApp.selectOne(Wrappers.lambdaQuery().eq(UserApp::getUserId, user.getId())); if (ObjectUtil.isNotEmpty(query)) { detail.set("ext", query.getUserExt()); } } else { UserOther userOther = new UserOther(); UserOther query = userOther.selectOne(Wrappers.lambdaQuery().eq(UserOther::getUserId, user.getId())); if (ObjectUtil.isNotEmpty(query)) { detail.set("ext", query.getUserExt()); } } userInfo.setDetail(detail); return userInfo; } @Override @Transactional(rollbackFor = Exception.class) public UserInfo userInfo(UserOauth userOauth) { UserOauth uo = userOauthService.getOne(Wrappers.query().lambda().eq(UserOauth::getUuid, userOauth.getUuid()).eq(UserOauth::getSource, userOauth.getSource())); UserInfo userInfo; if (Func.isNotEmpty(uo) && Func.isNotEmpty(uo.getUserId())) { userInfo = this.userInfo(uo.getUserId()); userInfo.setOauthId(Func.toStr(uo.getId())); } else { userInfo = new UserInfo(); if (Func.isEmpty(uo)) { userOauthService.save(userOauth); userInfo.setOauthId(Func.toStr(userOauth.getId())); } else { userInfo.setOauthId(Func.toStr(uo.getId())); } User user = new User(); user.setAccount(userOauth.getUsername()); user.setTenantId(userOauth.getTenantId()); userInfo.setUser(user); userInfo.setRoles(Collections.singletonList(GUEST_NAME)); } return userInfo; } @Override public boolean grant(String userIds, String roleIds) { User user = new User(); user.setRoleId(roleIds); return this.update(user, Wrappers.update().lambda().in(User::getId, Func.toLongList(userIds))); } @Override public boolean resetPassword(String userIds) { User user = new User(); user.setPassword(DigestUtil.encrypt(CommonConstant.DEFAULT_PASSWORD)); user.setUpdateTime(DateUtil.now()); return this.update(user, Wrappers.update().lambda().in(User::getId, Func.toLongList(userIds))); } @Override public boolean updatePassword(Long userId, String oldPassword, String newPassword, String newPassword1) { User user = getById(userId); if (!newPassword.equals(newPassword1)) { throw new ServiceException("请输入正确的确认密码!"); } if (!user.getPassword().equals(DigestUtil.hex(oldPassword))) { throw new ServiceException("原密码不正确!"); } //获取用户采用的密码策略 Strategy strategy = sysClient.getByUserId(userId).getData(); if(ObjectUtil.isEmpty(strategy)) { throw new ServiceException("当前用户未应用密码策略!"); } //密码长度校验 if(newPassword1.length() < strategy.getMinPwdLen() || newPassword1.length() > strategy.getMaxPwdLen()){ throw new ServiceException("密码中必须含有【"+strategy.getCombinationNames()+"】中的【"+strategy.getRequiredType()+"】种密码组合方式,且密码长度必须在【"+strategy.getMinPwdLen()+"-"+strategy.getMaxPwdLen()+"】范围内"); } List regexs = sysClient.getRegexByList(Arrays.asList(strategy.getCombinationIds().split(","))).getData(); //判断是否满足组合方式中的必填种类数 int reqType = 0; for (int i = 0; i < regexs.size(); i++) { if(reqType>=strategy.getRequiredType()){ break; } if(!Func.isEmpty(RegexUtil.findResult(regexs.get(i),newPassword1))){ reqType++; } } String resException = "密码中必须含有【"+strategy.getCombinationNames()+"】中的【"+strategy.getRequiredType()+"】种类型,请重新输入密码!"; if(reqTypeupdate().lambda() .set(User::getPassword, DigestUtil.hex(DigestUtils.md5DigestAsHex((newPassword1).getBytes()))) .set(User::getStrategyUpdateStatus,CommonConstant.TOP_PARENT_ID) .set(User::getPwdUpdateTime,new Date()) .eq(User::getId, userId)); } @Override public boolean removeUser(String userIds) { if (Func.contains(Func.toLongArray(userIds), AuthUtil.getUserId())) { throw new ServiceException("不能删除本账号!"); } return deleteLogic(Func.toLongList(userIds)); } @Override @Transactional(rollbackFor = Exception.class) public void importUser(List data, Boolean isCovered) { data.forEach(userExcel -> { User user = Objects.requireNonNull(BeanUtil.copy(userExcel, User.class)); // 设置用户平台 user.setUserType(Func.toInt(DictCache.getKey(DictEnum.USER_TYPE, userExcel.getUserTypeName()), 1)); // 设置部门ID user.setDeptId(Func.toStrWithEmpty(SysCache.getDeptIds(userExcel.getTenantId(), userExcel.getDeptName()), StringPool.EMPTY)); // 设置岗位ID user.setPostId(Func.toStrWithEmpty(SysCache.getPostIds(userExcel.getTenantId(), userExcel.getPostName()), StringPool.EMPTY)); // 设置角色ID user.setRoleId(Func.toStrWithEmpty(SysCache.getRoleIds(userExcel.getTenantId(), userExcel.getRoleName()), StringPool.EMPTY)); // 设置租户ID if (!AuthUtil.isAdministrator() || StringUtil.isBlank(user.getTenantId())) { user.setTenantId(AuthUtil.getTenantId()); } // 覆盖数据 if (isCovered) { // 查询用户是否存在 User oldUser = UserCache.getUser(userExcel.getTenantId(), userExcel.getAccount()); if (oldUser != null && oldUser.getId() != null) { user.setId(oldUser.getId()); this.updateUser(user); return; } } // 获取默认密码配置 String initPassword = ParamCache.getValue(DEFAULT_PARAM_PASSWORD); user.setPassword(initPassword); this.submit(user); }); } @Override public List exportUser(Wrapper queryWrapper) { List userList = baseMapper.exportUser(queryWrapper); userList.forEach(user -> { user.setUserTypeName(DictCache.getValue(DictEnum.USER_TYPE, user.getUserType())); user.setRoleName(StringUtil.join(SysCache.getRoleNames(user.getRoleId()))); user.setDeptName(StringUtil.join(SysCache.getDeptNames(user.getDeptId()))); user.setPostName(StringUtil.join(SysCache.getPostNames(user.getPostId()))); }); return userList; } @Override @Transactional(rollbackFor = Exception.class) public boolean registerGuest(User user, Long oauthId) { Tenant tenant = SysCache.getTenant(user.getTenantId()); if (tenant == null || tenant.getId() == null) { throw new ServiceException("租户信息错误!"); } UserOauth userOauth = userOauthService.getById(oauthId); if (userOauth == null || userOauth.getId() == null) { throw new ServiceException("第三方登陆信息错误!"); } user.setRealName(user.getName()); user.setAvatar(userOauth.getAvatar()); user.setRoleId(StringPool.MINUS_ONE); user.setDeptId(StringPool.MINUS_ONE); user.setPostId(StringPool.MINUS_ONE); boolean userTemp = this.submit(user); userOauth.setUserId(user.getId()); userOauth.setTenantId(user.getTenantId()); boolean oauthTemp = userOauthService.updateById(userOauth); return (userTemp && oauthTemp); } @Override public boolean updatePlatform(Long userId, Integer userType, String userExt) { if (userType.equals(UserEnum.WEB.getCategory())) { UserWeb userWeb = new UserWeb(); UserWeb query = userWeb.selectOne(Wrappers.lambdaQuery().eq(UserWeb::getUserId, userId)); if (ObjectUtil.isNotEmpty(query)) { userWeb.setId(query.getId()); } userWeb.setUserId(userId); userWeb.setUserExt(userExt); return userWeb.insertOrUpdate(); } else if (userType.equals(UserEnum.APP.getCategory())) { UserApp userApp = new UserApp(); UserApp query = userApp.selectOne(Wrappers.lambdaQuery().eq(UserApp::getUserId, userId)); if (ObjectUtil.isNotEmpty(query)) { userApp.setId(query.getId()); } userApp.setUserId(userId); userApp.setUserExt(userExt); return userApp.insertOrUpdate(); } else { UserOther userOther = new UserOther(); UserOther query = userOther.selectOne(Wrappers.lambdaQuery().eq(UserOther::getUserId, userId)); if (ObjectUtil.isNotEmpty(query)) { userOther.setId(query.getId()); } userOther.setUserId(userId); userOther.setUserExt(userExt); return userOther.insertOrUpdate(); } } @Override public UserVO platformDetail(User user) { User detail = baseMapper.selectOne(Condition.getQueryWrapper(user)); UserVO userVO = UserWrapper.build().entityVO(detail); if (userVO.getUserType().equals(UserEnum.WEB.getCategory())) { UserWeb userWeb = new UserWeb(); UserWeb query = userWeb.selectOne(Wrappers.lambdaQuery().eq(UserWeb::getUserId, user.getId())); if (ObjectUtil.isNotEmpty(query)) { userVO.setUserExt(query.getUserExt()); } } else if (userVO.getUserType().equals(UserEnum.APP.getCategory())) { UserApp userApp = new UserApp(); UserApp query = userApp.selectOne(Wrappers.lambdaQuery().eq(UserApp::getUserId, user.getId())); if (ObjectUtil.isNotEmpty(query)) { userVO.setUserExt(query.getUserExt()); } } else { UserOther userOther = new UserOther(); UserOther query = userOther.selectOne(Wrappers.lambdaQuery().eq(UserOther::getUserId, user.getId())); if (ObjectUtil.isNotEmpty(query)) { userVO.setUserExt(query.getUserExt()); } } return userVO; } @Override public Long checkRenAndExpr(Long userId) { //超级管理员直接返回不需要提醒密码修改 if(adminUserId.equals(userId)){ return 0L; } QueryWrapper wrapper = Wrappers.query().eq("ID", userId); //获取到密码修改时间 Date pwdUpdateTime = this.getOne(wrapper).getPwdUpdateTime(); Long pwdupdateday = 0L; if(!Func.isEmpty(pwdUpdateTime)){ pwdupdateday = dateToDay(pwdUpdateTime); } Strategy strategy = sysClient.getByUserId(userId).getData(); //是否提醒通过最后一次修改密码的时间加上过期时间减去当前时间,如果小于过期提醒时间就进行提醒,如果<=0就提醒必须修改密码 long reminder = pwdupdateday+strategy.getExpirationTime()-dateToDay(new Date()); //提醒用户必须修改密码 if(reminder<=0){ return -1L; } //提醒用户还有多久过期 if(reminder<=strategy.getReminderTime()){ long res = (strategy.getReminderTime()+pwdupdateday)-dateToDay(new Date()); return res; } //代表正常状态还未到提醒与过期时间,既不提醒也不要求修改 return 0L; } @Override public boolean updateByUseStrategyId(List userIds) { return this.update(Wrappers.lambdaUpdate().in(User::getId, userIds).set(User::getStrategyUpdateStatus,CommonConstant.IS_DEFAULT)); } /** * 时间格式转天 * @param date * @return */ private Long dateToDay(Date date){ long time = date.getTime(); return time/(1000 * 60 * 60 * 24); } }