bocloud.sms/bocloud.sms.service/src/main/java/com/bocloud/sms/service/UserServiceImpl.java

1820 lines
84 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.bocloud.sms.service;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.boot.model.BocloudStatus;
import com.bocloud.sms.entity.*;
import com.bocloud.sms.enums.YkInf;
import com.bocloud.sms.interfaces.UserService;
import com.bocloud.sms.model.*;
import com.bocloud.sms.repository.*;
import com.bocloud.sms.service.utils.ExportUtil;
import com.bocloud.sms.service.utils.ImportExcelUtil;
import com.bocloud.sms.service.utils.YkUtils;
import com.bocloud.sms.utils.FavoriteComparator;
import com.google.common.collect.Lists;
import com.megatron.common.encrypt.AESEncryptor;
import com.megatron.common.encrypt.Encryptor;
import com.megatron.common.encrypt.SHAEncryptor;
import com.megatron.common.enums.BaseStatus;
import com.megatron.common.exception.InternalServerException;
import com.megatron.common.model.*;
import com.megatron.common.model.RequestContext.Catalog;
import com.megatron.common.utils.Common;
import com.megatron.common.utils.ListTool;
import com.megatron.common.utils.MapTools;
import com.megatron.common.utils.Tokens;
import com.megatron.entity.bean.GenericEntity;
import com.megatron.framework.core.CurrentService;
import com.megatron.framework.lock.AutoCloseLock;
import com.megatron.framework.lock.LockFactory;
import io.jsonwebtoken.SignatureAlgorithm;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.bocloud.sms.service.utils.ExportUtil.exportExcel;
import static com.bocloud.sms.service.utils.ExportUtil.getCellStringValue;
/**
* 用户抽象Service接口实现类
*
* @author tyl
*/
@Service
@Slf4j
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final CurrentService currentService;
private final StringRedisTemplate redisTemplate;
private final LockFactory lockFactory;
private final UserRepository userRepository;
private final RoleRepository roleRepository;
private final TenantRepository tenantRepository;
private final PermissionRepository permissionRepository;
private final ProjectRepository projectRepository;
private final AccountSecurityRepository securityRepository;
private final DepartmentRepository departmentRepository;
private final ThreadPoolTaskExecutor taskExecutor;
private final UserProjectRepository userProjectRepository;
private final LoginRecordRepository loginRecordRepository;
private final UserRoleRepository userRoleRepository;
private final ManagerRoleRepository managerRoleRepository;
private final FavoriteRepository favoriteRepository;
private final CloudServiceBeanRepository cloudServiceBeanRepository;
private final ApiPermissionRepository apiPermissionRepository;
private final YkUtils ykUtils;
/**
* 分页查询用户列表
*
* @param pager 分页对象
* @param requestContext 请求对象
* @return
*/
@Override
public GeneralResult<GridBean<User>> list(Pager pager, RequestContext requestContext) {
List<Param> params = Optional.ofNullable(pager.getParams()).orElse(new ArrayList<>());
HashMap<String, String> map = new HashMap<>(4);
map.put("gmtCreate", Common.ONE);
map.put("id", Common.ONE);
Map<String, String> sorter = !pager.getSorter().isEmpty() ? pager.getSorter() : map;
List<User> list;
int total;
GridBean<User> gridBean;
Long roleId = null;
// 有参数时判断是否有租户id
for (Param next : params) {
Map<String, Object> paramMap = next.getParam();
if (paramMap.containsKey("projectId")) {
Integer projectId = (Integer) paramMap.get("projectId");
Param param = new Param(MapTools.simpleMap("projectId", projectId), Sign.EQ);
params.add(param);
total = userRepository.projectUserCount(params);
list = userRepository.listProjectUser(pager.getPage(), pager.getRows(), params, sorter);
for (User user : list) {
Department department = departmentRepository.query(user.getDepartId());
if (department != null) {
user.setDepartmentName(department.getName());
}
}
gridBean = new GridBean<>(pager.getPage(), pager.getRows(), total, list);
return new GeneralResult<>(true, gridBean, "查询项目用户成功");
}
if (paramMap.containsKey("roleId")) {
roleId = Long.valueOf(paramMap.get("roleId").toString());
paramMap.remove("roleId");
}
}
// 无参数租户请求获取用户列表把requestContext里的租户Id作为参数
if (!Catalog.Manager.equals(requestContext.getCatalog())) {
Map<String, Object> tenantMap = MapTools.simpleMap("tenantId", requestContext.getTenant());
Param param = new Param(tenantMap, Sign.EQ);
params.add(param);
}
total = userRepository.count(params, roleId);
Map<Long, Department> departmentMap =
departmentRepository.listAll().stream().collect(Collectors.toMap(Department::getId, Function.identity()));
if (pager.getSimple()) {
List<SimpleBean> beans = userRepository.list(params, sorter, roleId);
gridBean = new GridBean(1, 1, total, beans);
} else {
list = userRepository.list(pager.getPage(), pager.getRows(), params, sorter, roleId);
list.forEach(user -> {
try {
List<String> roles = roleRepository.listByUser(user.getId()).stream().map(GenericEntity::getName)
.collect(Collectors.toList());
user.setRoleNames(roles);
Department department = departmentMap.get(user.getDepartId());
if (department != null) {
user.setDepartmentName(department.getName());
List<Long> deptIdTree = getDeptIdTree(departmentMap, department);
Collections.reverse(deptIdTree);
String string = JSONObject.toJSONString(deptIdTree);
user.setDepartIds(string);
} else {
user.setDepartIds("[]");
}
} catch (Exception e) {
log.error("list user {} role names error!", user.getAccount(), e);
}
});
gridBean = new GridBean<>(pager.getPage(), pager.getRows(), total, list);
}
return new GeneralResult<>(true, gridBean, "查询用户成功");
}
private List<Long> getDeptIdTree(Map<Long, Department> departmentMap, Department department) {
List<Long> result = new ArrayList<>();
result.add(department.getId());
Department parent = departmentMap.get(department.getParentId());
if (parent != null) {
List<Long> deptIdTree = getDeptIdTree(departmentMap, parent);
result.addAll(deptIdTree);
}
return result;
}
/**
* 用户登录
*
* @param account 账号
* @param password 密码
* @param sessionId 会话id
* @param requestIp 请求ip
* @return
* @throws InternalServerException
*/
@SneakyThrows
@Override
@Transactional(rollbackFor = InternalServerException.class)
public GeneralResult<Map<String, Object>> login(String account, String password, String sessionId, String requestIp,
Boolean isManager) throws InternalServerException {
log.info("UserService接受到调用请求");
long start;
LoginRecord loginRecord = new LoginRecord();
loginRecord.setRequestIp(requestIp);
String currentServiceHost = currentService.getService().getHost();
log.info("currentServiceHost={}", currentServiceHost);
loginRecord.setResponseIp(currentServiceHost);
loginRecord.setAccount(account);
loginRecord.setCategory(LoginRecord.Category.User);
loginRecord.setGmtCreate(new Date());
// 判断用户是否存在
User user;
AccountSecurity security;
log.info("Before Try");
try {
log.info("Start Try");
start = System.currentTimeMillis();
user = userRepository.getByAccount(account);
log.info("查询用户信息耗时{}ms", System.currentTimeMillis() - start);
// 注释掉,允许普通用户也可登录
/*if (isManager) {
if (!user.getIsManager()) {
handleLoginLog(false, "该账号没有管理权限", loginRecord);
return new GeneralResult<>(false, "该账号没有管理权限");
}
}*/
if (null == user) {
log.warn("User is null");
handleLoginLog(false, "账号或密码错误", loginRecord);
return new GeneralResult<>(false, "账号或密码错误");
}
start = System.currentTimeMillis();
security = securityRepository.getByTarget(user.getId(), Catalog.User);
log.info("查询用户安全耗时{}ms", System.currentTimeMillis() - start);
if (null == security) {
log.warn("Security is null");
handleLoginLog(false, "账号或密码错误", loginRecord);
return new GeneralResult<>(false, "账号或密码错误");
}
// 对前端传过来的密码进行解密
Encryptor encryptor = new AESEncryptor();
password = encryptor.decrypt(password.trim(), null);
if (!StringUtils.hasText(password)) {
handleLoginLog(false, "账号或密码错误", loginRecord);
return new GeneralResult<>(false, "账号或密码错误");
}
// 密码加密
encryptor = new SHAEncryptor();
String encryptString = encryptor.encrypt(password, security.getSalt());
if (null == encryptString || !encryptString.equals(user.getPassword())) {
log.warn("Wrong user account or password");
handleLoginLog(false, "账号或密码错误", loginRecord);
return new GeneralResult<>(false, "账号或密码错误");
}
} catch (Exception e) {
handleLoginLog(false, "账号或密码错误", loginRecord);
log.error("Get User fail by account:", e);
return new GeneralResult<>(false, "账号或密码错误");
}
// 更新用户登录状态
try {
// 用户状态校验
if (user.getStatus().equals(BaseStatus.ABNORMAL.name())) {
handleLoginLog(false, "账号已冻结", loginRecord);
return new GeneralResult<>(false, "冻结用户无法登录");
}
if (user.getStatus().equals(BocloudStatus.Basic.EXPIRED.name())) {
handleLoginLog(false, "账号已过期", loginRecord);
return new GeneralResult<>(false, "账号已过期,无法登录");
}
start = System.currentTimeMillis();
Tenant tenant = tenantRepository.query(user.getTenantId());
log.info("查询用户租户耗时{}ms", System.currentTimeMillis() - start);
if (tenant != null && tenant.getStatus().equals(BocloudStatus.Basic.EXPIRED.name())) {
handleLoginLog(false, "所属租户账号已过期", loginRecord);
return new GeneralResult<>(false, "所属租户账号已过期,无法登录,请联系管理员!");
}
if (null == user.getTenantId() || 0L == user.getTenantId()) {
if (!isManager) {
handleLoginLog(false, "用户没有所属租户,不能登录该系统", loginRecord);
return new GeneralResult<>(false, "用户没有所属租户,不能登录该系统!");
}
}
user.setLoginStatus(true);
user.setSessionId(sessionId);
Date lastLoginDate = user.getLastLoginDate();
user.setLastLoginDate(new Date());
start = System.currentTimeMillis();
userRepository.update(user);
log.info("更新用户信息耗时{}ms", System.currentTimeMillis() - start);
user.setLastLoginDate(lastLoginDate);
} catch (Exception e) {
handleLoginLog(false, "更新用户登录状态失败", loginRecord);
log.error("Update user login status fail", e);
throw new InternalServerException("更新用户登录状态失败", e, e.getMessage());
}
try {
// 构建返回数据
isManager = Optional.ofNullable(isManager).orElse(false);
start = System.currentTimeMillis();
if (isManager) {
// 刷新权限缓存
flushRoleApiPermission(true, user.getId());
} else {
flushRoleApiPermission(false, user.getTenantId());
}
log.info("flushRoleApiPermission耗时{}ms", System.currentTimeMillis() - start);
Map<String, Object> map = getResultMap(isManager, user, security);
if (map != null) {
handleLoginLog(true, "用户登录成功", loginRecord);
return new GeneralResult<>(true, map, "用户登录成功");
} else {
handleLoginLog(true, "用户登录失败", loginRecord);
return new GeneralResult<>(false, "用户登录失败");
}
} catch (Exception e) {
handleLoginLog(true, "用户登录失败:" + e.getMessage(), loginRecord);
return new GeneralResult<>(false, "用户登录失败");
}
}
private Map<String, Object> getResultMap(Boolean isManager, User user, AccountSecurity security) {
try {
Map<String, Object> map;
if (isManager) {
map = MapTools.simpleMap("manager", user);
map.put(Common.API_KEY, security.getApiKey());
map.put("accountCategory", Catalog.Manager.name());
String token = buildToken(true, user, security);
map.put(Common.TOKEN, token);
} else {
map = MapTools.simpleMap(Common.USER, user);
map.put(Common.API_KEY, security.getApiKey());
map.put("accountCategory", Catalog.User.name());
String token = buildToken(false, user, security);
map.put(Common.TOKEN, token);
}
return map;
} catch (Exception e) {
log.error("get login result error,", e);
return null;
}
}
private String buildToken(Boolean isManager, User user, AccountSecurity security) {
long start;
// 构建token
Map<String, Object> header = MapTools.simpleMap("alg", SignatureAlgorithm.HS256.getValue());
header.put("typ", "JWT");
Map<String, Object> payload = MapTools.simpleMap(Common.ACCOUNT, user.getAccount());
payload.put(Common.API_KEY, security.getApiKey());
payload.put(Common.UUID, user.getId());
payload.put(Common.NAME, user.getName());
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MONTH, 3);
if (isManager) {
payload.put("catalog", Catalog.Manager.name());
} else {
payload.put("catalog", Catalog.User.name());
payload.put(Common.TENANTID, user.getTenantId());
payload.put("tenantName", user.getTenantName());
payload.put("tenantAccount", user.getTenantAccount());
}
// 加密jwt生成token并存入session和cookie
String token = Tokens.generate(header, payload, calendar.getTime());
String tokenKey = isManager ? "token_" + Catalog.Manager.name() + "_" + user.getId()
: "token_" + Catalog.User.name() + "_" + user.getId();
start = System.currentTimeMillis();
this.redisTemplate.delete(tokenKey + "_o");
log.info("删除Redis的Token耗时{}ms", System.currentTimeMillis() - start);
HashMap<String, Object> tokenJson = new HashMap<>(8);
tokenJson.put("token", token);
tokenJson.put("refreshTime", LocalDateTime.now().plusMinutes(10).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
start = System.currentTimeMillis();
redisTemplate.opsForHash().putAll(tokenKey + "_n", tokenJson);
this.redisTemplate.expire(tokenKey + "_n", 30L, TimeUnit.MINUTES);
log.info("写入Redis的Token耗时{}ms", System.currentTimeMillis() - start);
return token;
}
private void flushRoleApiPermission(Boolean isManager, Long id) {
List<Long> roleIds;
// 管理端API权限
if (isManager) {
roleIds = roleRepository.listManagerApiRole(id).stream().map(Role::getId).collect(Collectors.toList());
} else {
// 自服务API权限
roleIds = roleRepository.getTenantUserRole().stream().map(Role::getId).collect(Collectors.toList());
}
List<ApiPermission> apiPermissions = apiPermissionRepository.listRoleApiPermission(roleIds);
Map<Long, List<ApiPermission>> rolePermissionMap =
apiPermissions.stream().collect(Collectors.groupingBy(ApiPermission::getRoleId));
for (Map.Entry<Long, List<ApiPermission>> rolePermissionEntry : rolePermissionMap.entrySet()) {
Long roleId = rolePermissionEntry.getKey();
Map<String, List<ApiPermission>> permissionMap =
rolePermissionEntry.getValue().stream().collect(Collectors.groupingBy(ApiPermission::getModule));
for (Map.Entry<String, List<ApiPermission>> permission : permissionMap.entrySet()) {
String module = permission.getKey();
List<String> patterns = permission.getValue().stream()
.map(s -> new String(Base64.getDecoder().decode(s.getPattern()))).collect(Collectors.toList());
if (!patterns.isEmpty()) {
redisTemplate.opsForHash().put("api_permission_" + roleId, module,
JSONObject.toJSONString(patterns));
}
}
}
}
/**
* 保存登录日志
*
* @param status 登录状态
* @param detail 日志详情
* @param record 日志对象
*/
private void handleLoginLog(boolean status, String detail, LoginRecord record) {
record.setStatus(status);
record.setDetail(detail);
try {
this.save(record);
} catch (Exception e) {
log.error("save login record error");
}
}
@Override
@Transactional
public Result create(UserBean userBean, RequestContext requestContext) {
User user = new User();
BeanUtils.copyProperties(userBean, user);
Assert.notNull(user, "user can't be null");
user.setCreatorId(requestContext.getTarget());
// 初始化密码
String salt = UUID.randomUUID().toString();
Encryptor encryptor = new SHAEncryptor();
// 查询创建者的租户信息并赋值给所创建的用户
if (Catalog.Tenant == requestContext.getCatalog()) {
user.setTenantId(requestContext.getTenant());
} else if (Catalog.Manager == requestContext.getCatalog()) {
user.setTenantId(null == userBean.getTenantId() ? 0L : userBean.getTenantId());
} else {
user.setTenantId(0L);
}
User existUser = userRepository.getByAccount(user.getAccount());
Assert.isNull(existUser, "该账号已存在");
User existEmailUser = userRepository.getByEmail(user.getEmail());
Assert.isNull(existEmailUser, "该邮箱已被注册");
// trx用户登录添加时密码处理
String password = encryptor.encrypt(userBean.getUserId() == null ? new AESEncryptor().decrypt(user.getPassword().trim(), null) : userBean.getPassword(), salt);
// String password = encryptor.encrypt(new AESEncryptor().decrypt(user.getPassword().trim(), null), salt);
user.setPassword(password);
// 关键信息去空
user.setAccount(user.getAccount().trim());
user.setName(user.getName().trim());
user.setStatus(BaseStatus.NORMAL.name());
user.setLoginStatus(false);
user.setLastPwdModifyDate(new Date());
user.setOrigin("SYSTEM");
userRepository.save(user);
String account = user.getAccount();
User cacheUser = userRepository.getByAccount(account);
redisTemplate.opsForValue().set(Catalog.User.name() + "_" + cacheUser.getId(), account);
redisTemplate.opsForValue().set(Catalog.User.name() + "_Name_" + cacheUser.getId(), cacheUser.getName());
// 构建用户随机数对象
AccountSecurity security = new AccountSecurity();
String data = Long.toString(System.currentTimeMillis());
String apiKey = encryptor.encrypt(data, Common.API_KEY);
String secKey = encryptor.encrypt(data, Common.SEC_KEY);
security.setTargetId(user.getId());
security.setCategory(AccountSecurity.Category.User);
security.setSalt(salt);
security.setApiKey(apiKey);
security.setSecKey(secKey);
security.setTenantId(user.getTenantId());
securityRepository.baseSave(security);
return new Result(true, "添加用户成功");
}
@Override
@Transactional
public Result modify(Long id, UserBean userBean, RequestContext requestContext) {
Assert.notNull(userBean, "user bean can't be null");
userBean.setName(userBean.getName().trim());
if (userBean.getTenantId() == null) {
userBean.setTenantId(0L);
}
String path = User.class.getSimpleName() + "_" + id;
try (AutoCloseLock lock = lockFactory.getACLock(path)) {
Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
Assert.isTrue(id.equals(userBean.getId()), "非法请求");
if (Catalog.User == requestContext.getCatalog()) {
Assert.isTrue(id.equals(requestContext.getTarget()), "非法请求");
}
User user = userRepository.query(id);
if (Catalog.Tenant == requestContext.getCatalog()) {
Assert.isTrue(requestContext.getTenant().equals(user.getTenantId()), "非法请求");
}
Assert.notNull(user, "用户不存在");
if (!userBean.getEmail().equals(user.getEmail())) {
Tenant existName = tenantRepository.getByEmail(userBean.getEmail());
Assert.isNull(existName, "该邮箱已被注册");
}
AccountSecurity security = null;
if (userBean.getTenantId() == null || !userBean.getTenantId().equals(user.getTenantId())) {
security = securityRepository.getByTarget(id, Catalog.User);
security.setTenantId(userBean.getTenantId());
}
// 判断是否修改有效期
long l = user.getExpiredDate() == null ? 0L : user.getExpiredDate().getTime();
if (userBean.getExpiredDate() != null &&
userBean.getExpiredDate().getTime() != l) {
if (!BocloudStatus.Basic.NORMAL.name().equals(user.getStatus())) {
user.setStatus(BocloudStatus.Basic.NORMAL.name());
}
}
BeanUtils.copyProperties(userBean, user, "password");
user.setMenderId(requestContext.getTarget());
boolean result = userRepository.update(user);
// 缓存更新用户姓名
redisTemplate.opsForValue().set(Catalog.User.name() + "_Name_" + user.getId(), user.getName());
if (result) {
if (security != null) {
securityRepository.update(security);
}
return new Result(true, "修改成功");
}
return new Result(false, "修改失败");
}
}
/**
* 删除用户信息
*
* @param id 用户id
* @param requestContext 请求对象
* @return
*/
@Override
@Transactional
public Result remove(Long id, RequestContext requestContext) {
String path = User.class.getSimpleName() + "_" + id;
try (AutoCloseLock lock = lockFactory.getACLock(path)) {
Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
if (RequestContext.Catalog.User == requestContext.getCatalog()) {
Assert.isTrue(id.equals(requestContext.getTarget()), "非法请求");
}
User user = userRepository.query(id);
if (Catalog.Tenant == requestContext.getCatalog()) {
Assert.isTrue(requestContext.getTenant().equals(user.getTenantId()), "非法请求");
}
Assert.notNull(user, "用户不存在!");
// 删除用户角色
userRoleRepository.unBindUserRole(id);
// 删除用户收藏数据
favoriteRepository.cancelFavorite(null, id, requestContext.getCatalog().name());
userRepository.delete(id, requestContext.getTarget());
// 删除用户账号安全表
securityRepository.delete(id, Catalog.User);
// 删除用户项目关联
this.userProjectRepository.unBindProject(id);
// 删除用户账号信息缓存
redisTemplate.delete(Catalog.User.name() + "_" + user.getId());
// redisTemplate.delete(Catalog.User.name() + "_Name_" + user.getId());
// 删除用户token
String tokenKey = Common.TOKEN + "_" + Catalog.User.name() + "_" + id;
redisTemplate.delete(tokenKey + "_n");
redisTemplate.delete(tokenKey + "_o");
return new Result(true, "删除用户成功");
}
}
@Override
public Result updateStatus(Long id, ActionModel.Action action, RequestContext requestContext)
throws InternalServerException {
String path = User.class.getSimpleName() + "_" + id;
try (AutoCloseLock lock = lockFactory.getACLock(path)) {
Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
User user = userRepository.query(id);
Assert.notNull(user, "用户信息不存在!");
Long menderId = requestContext.getTarget();
switch (action) {
case active:
Assert.isTrue(!id.equals(menderId), "用户不能冻结当前登录的用户。");
return userRepository.active(id, menderId) ? new Result(true, "解冻用户成功")
: new Result(false, "解冻用户失败");
case lock:
if (userRepository.lock(id, menderId)) {
// 删除用户token
String tokenKey = Common.TOKEN + "_" + Catalog.User.name() + "_" + id;
redisTemplate.delete(tokenKey + "_n");
redisTemplate.delete(tokenKey + "_o");
return new Result(true, "冻结用户成功");
} else {
return new Result(false, "冻结用户失败");
}
default:
break;
}
return new Result(false, "不支持的操作");
} catch (Exception e) {
log.error("update user status fail:", e);
return GeneralResult.FAILED("修改用户状态失败," + e.getMessage());
}
}
@Override
public Result batchLock(List<Long> ids, RequestContext context) {
try {
boolean result = userRepository.batchUpdateStatus(ids, context.getTarget(), BaseStatus.ABNORMAL);
for (Long id : ids) {
String tokenKey = Common.TOKEN + "_" + Catalog.User.name() + "_" + id;
redisTemplate.delete(tokenKey + "_n");
redisTemplate.delete(tokenKey + "_o");
}
return result ? new Result(true, "批量冻结用户成功") : new Result(false, "批量冻结用户失败");
} catch (Exception e) {
log.error("batch locked users fail:", e);
return new Result(false, "批量冻结用户失败," + e.getMessage());
}
}
@Override
public Result batchActive(List<Long> ids, RequestContext context) {
try {
boolean result = userRepository.batchUpdateStatus(ids, context.getTarget(), BaseStatus.NORMAL);
return result ? new Result(true, "批量解冻用户成功") : new Result(false, "批量解冻用户失败");
} catch (Exception e) {
log.error("batch active users fail:", e);
return new Result(false, "批量解冻用户失败," + e.getMessage());
}
}
@Transactional
@Override
public Result batchRemove(List<Long> ids, RequestContext context) {
for (Long id : ids) {
this.remove(id, context);
}
return new Result(true, "用戶批量刪除成功");
}
@Override
@Transactional
public Result changePwd(Long id, String oldPassword, String password, RequestContext requestContext) {
//1 需要优先调用运控系统修改密码接口,修改完成才能同步本端数据库
// 根据userId获取运控系统用户信息
log.info("查询当前用户信息userId: " + id);
JSONObject params = new JSONObject();
params.put("userId", String.valueOf(id));
params.put("oldPwd", oldPassword);
params.put("newPwd", password);
//请求运控修改密码机接口
JSONObject result = ykUtils.call(YkInf.updateUserPwd, params, JSONObject.class);
if (result.getInteger("returnCode") == 1) {
log.info("运控密码修改成功");
String path = User.class.getSimpleName() + "_" + id;
try (AutoCloseLock lock = lockFactory.getACLock(path)) {
Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
Assert.isTrue(id.equals(requestContext.getTarget()), "非法请求");
User user = userRepository.query(id);
Assert.notNull(user, "用户信息不存在!");
String salt = UUID.randomUUID().toString();
// 加密
SHAEncryptor sha = new SHAEncryptor();
Encryptor encryptor = new AESEncryptor();
// 对原密码解密,并校验。
oldPassword = encryptor.decrypt(oldPassword.trim(), null);
Assert.isTrue(StringUtils.hasText(oldPassword), "旧密码不存在");
Result checkResult = this.check(id, oldPassword);
if (checkResult.isFailed()) {
return checkResult;
}
// 对前端传过来的密码进行解密
password = encryptor.decrypt(password.trim(), null);
Assert.isTrue(StringUtils.hasText(password), "新密码不存在。");
String encrypt = sha.encrypt(password, salt);
user.setPassword(encrypt);
user.setLastPwdModifyDate(new Date());
userRepository.update(user);
// 准备随机数数据
AccountSecurity security = securityRepository.getByTarget(user.getId(), Catalog.User);
security.setSalt(salt);
// 更新随机数
securityRepository.update(security);
return new Result(true, "修改密码成功");
}
} else {
return new Result(true, "修改密码失败");
}
}
@Override
public Result resetPwd(Long id, String password, RequestContext requestContext) {
String path = User.class.getSimpleName() + "_" + id;
try (AutoCloseLock lock = lockFactory.getACLock(path)) {
Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
String salt = UUID.randomUUID().toString();
SHAEncryptor sha = new SHAEncryptor();
User user = userRepository.query(id);
Assert.notNull(user, "用户息不存在!");
user.setPassword(sha.encrypt(new AESEncryptor().decrypt(password.trim(), null), salt));
user.setMenderId(requestContext.getTarget());
user.setLastPwdModifyDate(new Date());
userRepository.update(user);
// 准备随机数数据
AccountSecurity userSecurity = securityRepository.getByTarget(user.getId(), Catalog.User);
userSecurity.setSalt(salt);
// 更新随机数
securityRepository.update(userSecurity);
return new Result(true, "重置密码成功");
} catch (Exception e) {
log.error("reset user password fail:", e);
return GeneralResult.FAILED("重置密码失败," + e.getMessage());
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public Result accredit(Long id, List<Long> roleIds, RequestContext requestContext) {
String path = User.class.getSimpleName() + "_" + id;
try (AutoCloseLock lock = lockFactory.getACLock(path)) {
Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
User user = userRepository.query(id);
Assert.notNull(user, "用户信息不存在");
if (requestContext.getCatalog().equals(Catalog.Manager)) {
List<ManagerRole> roles =
roleIds.stream().map(role -> new ManagerRole(id, role)).collect(Collectors.toList());
// 解绑管理员下角色
managerRoleRepository.unBindManagerRole(id);
if (!roles.isEmpty()) {
this.batchSaveManagerRoles(roles);
}
} else {
List<UserRole> roles =
roleIds.stream().map(role -> new UserRole(id, role)).collect(Collectors.toList());
// 解绑用户角色
userRoleRepository.unBindUserRole(id);
if (!roles.isEmpty()) {
this.batchSaveUserRoles(roles);
}
}
user.setMenderId(requestContext.getTarget());
userRepository.update(user);
return new Result(true, "用户角色授权成功");
} catch (Exception e) {
log.error("accredit user role fail:", e);
throw new InternalServerException("授权用户角色失败," + e.getMessage(), e, e.getMessage());
}
}
/**
* 批量绑定用户角色
*
* @param roles 用户角色集合
*/
@Transactional
public void batchSaveUserRoles(List<UserRole> roles) {
for (UserRole userRole : roles) {
userRoleRepository.save(userRole);
}
}
/**
* 批量保存管理员角色
*
* @param roles 角色集合
*/
private void batchSaveManagerRoles(List<ManagerRole> roles) {
// userRepository.bindManagerRoles(roles);
for (ManagerRole managerRole : roles) {
managerRoleRepository.save(managerRole);
}
}
@Override
public GeneralResult<User> detail(Long id) {
User user = userRepository.query(id);
Assert.notNull(user, "用户不存在。");
if (null != user.getTenantId() && 0L != user.getTenantId()) {
Tenant tenant = tenantRepository.query(user.getTenantId());
if (null != tenant) {
user.setTenantName(tenant.getName());
}
}
// 查询用户关联的项目
List<UserProject> userProjects = userProjectRepository.listUserProjectByUserId(id);
List<Long> projectIds = Lists.newArrayList();
if (!ListTool.isEmpty(userProjects)) {
for (UserProject userProject : userProjects) {
projectIds.add(userProject.getProjectId());
}
}
user.setProjectIds(projectIds);
List<String> roleNames = new ArrayList<>();
List<Role> roles = roleRepository.listByUser(user.getId());
if (!roles.isEmpty()) {
for (Role role : roles) {
roleNames.add(role.getName());
}
}
//给用户设置管理端的角色名
List<Role> managerRoles = roleRepository.listByManager(user.getId());
if (!ListTool.isEmpty(managerRoles)) {
for (Role role : managerRoles) {
if (!roleNames.contains(role.getName())) {
roleNames.add(role.getName());
}
}
}
// 给用户设置角色名
user.setRoleNames(roleNames);
Department department = departmentRepository.query(user.getDepartId());
if (department != null) {
user.setDepartmentName(department.getName());
}
return new GeneralResult<>(true, user, "查询用户详情成功");
}
/**
* 获取用户安全密钥
*
* @param apiKey api密钥
* @return
*/
@Override
public GeneralResult<AccountSecurity> getAccountSecurity(String apiKey) {
try {
AccountSecurity security = securityRepository.getByApiKey(apiKey, Catalog.User);
return new GeneralResult<>(true, security, "获取安全密钥成功");
} catch (Exception e) {
log.error("get secKey fail:", e);
return new GeneralResult<>(false, "获取安全密钥失败");
}
}
/**
* 校验用户密码
*
* @param id 用户id
* @param password 密码
* @return
*/
@Override
public Result check(Long id, String password) {
try {
User user = userRepository.query(id);
AccountSecurity security = securityRepository.getByTarget(id, Catalog.User);
Assert.isTrue(null != user && null != security, "原密码验证失败。");
SHAEncryptor sha = new SHAEncryptor();
String encrypt = sha.encrypt(password, security.getSalt());
Assert.isTrue(null != encrypt && encrypt.equals(user.getPassword()), "原密码验证失败");
return new Result(true, "原密码正确");
} catch (Exception e) {
log.error("old password not correct:", e);
return new Result(false, e.getMessage());
}
}
/**
* 根据项目id获取用户项目关联
*
* @param projectId
* @param requestContext
* @return
*/
@Override
public GeneralResult<List<User>> listProjectUser(Long projectId, RequestContext requestContext) {
try {
Project project = projectRepository.query(projectId);
Assert.notNull(project, "项目信息不存在");
List<User> userList;
if (requestContext.getCatalog().equals(Catalog.Manager)) {
userList = userRepository.list();
} else {
userList = userRepository.listByTenant(project.getTenantId());
}
List<UserProject> userProjects = userProjectRepository.listUserProject(projectId);
List<Long> managerIds = new ArrayList<>();
List<Long> userIds = new ArrayList<>();
for (UserProject userProject : userProjects) {
if (userProject.getProjectAdmin()) {
managerIds.add(userProject.getUserId());
} else {
userIds.add(userProject.getUserId());
}
}
for (User user : userList) {
if (managerIds.contains(user.getId())) {
user.setChecked(true);
user.setProjectManager(true);
} else if (userIds.contains(user.getId())) {
user.setChecked(true);
user.setProjectManager(false);
} else {
user.setChecked(false);
user.setProjectManager(false);
}
}
return new GeneralResult<>(true, userList, "查询成功");
} catch (Exception e) {
log.error("Get error message", e);
return new GeneralResult<>(false, "查询失败:" + e.getMessage());
}
}
@Override
public GeneralResult<List<User>> listProjectManager(Long id) {
try {
List<User> projectManagers = userRepository.getProjectManagers(id);
return new GeneralResult<>(true, projectManagers, "查询成功");
} catch (Exception e) {
log.error("list project managers message", e);
return new GeneralResult<>(false, "查询失败:" + e.getMessage());
}
}
/**
* 校验用户状态
*
* @param id 用户id
* @param token token
* @return
*/
@Override
public Result checkUser(Long id, String token) {
try {
User user = userRepository.query(id);
if (null != user) {
if (BaseStatus.ABNORMAL.name().equals(user.getStatus())) {
return new Result(false, "该用户已被冻结,请联系管理员进行解冻!");
}
if ("LOGOUT".equals(user.getStatus())) {
return new Result(false, "该用户已被注销!");
}
String tokenKey = Common.TOKEN + "_" + Catalog.User + "_" + id;
String newTokenCache = this.redisTemplate.opsForValue().get(tokenKey + "_n");
if (!token.equals(newTokenCache)) {
return GeneralResult.FAILED("此用户已在别处登录!");
}
return new Result(true, "");
} else {
return new Result(false, "查询用户失败!");
}
} catch (Exception e) {
log.error("check user login fail:", e);
return new Result(false, "检查用户登录失败!");
}
}
/**
* 用户退出登录
*
* @param id 用户id
* @return
* @throws InternalServerException
*/
@Override
@Transactional(rollbackFor = InternalServerException.class)
public Result logout(Long id) throws InternalServerException {
try {
User user = userRepository.query(id);
if (user != null) {
user.setLoginStatus(false);
user.setSessionId("");
userRepository.update(user);
String tokenKey = Common.TOKEN + "_" + Catalog.User.name() + "_" + id;
redisTemplate.delete(tokenKey + "_n");
redisTemplate.delete(tokenKey + "_o");
String managerTokenKey = Common.TOKEN + "_" + Catalog.Manager.name() + "_" + id;
redisTemplate.delete(managerTokenKey + "_n");
redisTemplate.delete(managerTokenKey + "_o");
}
return new Result(true, "用户退出成功!");
} catch (Exception e) {
log.error("get user fail:", e);
throw new InternalServerException("获取用户信息失败!", e, e.getMessage());
}
}
/**
* 查询用户角色列表
*
* @param id 用户id
* @param requestContext 请求对象
* @return
*/
@Override
public GeneralResult<List<Role>> listRoles(Long id, String condition, RequestContext requestContext) {
try {
List<Role> roles;
if (requestContext.getCatalog().equals(Catalog.Manager)) {
if (null != condition) {
if ("cmdbQueryRoles".equalsIgnoreCase(condition)) {
roles = this.roleRepository.listByManager(id);
return new GeneralResult<>(true, roles, "查询成功");
}
}
List<Role> list = this.roleRepository.listByManager(id);
roles = this.roleRepository.listManagerRole();
if (null == roles || roles.isEmpty()) {
return new GeneralResult<>(false, "查询所有角色失败!");
}
// 构建返回对象设置check值
for (Role role : roles) {
if (null != list && !list.isEmpty()) {
for (Role r : list) {
// 管理员拥有的角色check设置为true前端显示用
if (role.getId().equals(r.getId())) {
role.setChecked(true);
}
}
}
}
} else {
roles = this.roleRepository.listByUser(id);
}
return new GeneralResult<>(true, roles, "查询成功");
} catch (Exception e) {
log.error("list permission by tenant id:", e);
return new GeneralResult<>(false, "查询失败", null, null);
}
}
/**
* 根据账号锁定用户
*
* @param account 用户账号
* @return
* @throws InternalServerException
*/
@Override
@Transactional(rollbackFor = InternalServerException.class)
public Result lockByAccount(String account) throws InternalServerException {
String path;
boolean result;
User user;
try {
user = userRepository.getByAccount(account);
Assert.notNull(user, "user data don't exists");
} catch (Exception e) {
log.error("get user data fail:", e);
return new Result(false, "获取用户信息失败");
}
path = User.class.getSimpleName() + "_" + user.getId();
try (AutoCloseLock lock = lockFactory.getACLock(path)) {
Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
result = userRepository.lock(user.getId(), 1L);
return result ? new Result(true, "冻结用户成功") : new Result(false, "冻结用户失败");
} catch (Exception e) {
log.error("freeze user fail:", e);
throw new InternalServerException("冻结用户失败", e, e.getMessage());
}
}
/**
* 保存用户登录数据
*
* @param
* @return
*/
@Override
@Transactional(rollbackFor = InternalServerException.class)
public Result save(LoginRecord loginRecord) throws InternalServerException {
String path = LoginRecord.class.getSimpleName() + "_" + loginRecord.getAccount();
try (AutoCloseLock lock = lockFactory.getACLock(path)) {
Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
long start = System.currentTimeMillis();
loginRecordRepository.save(loginRecord);
log.info("保存登录记录耗时{}ms", System.currentTimeMillis() - start);
return new Result(true, "租户登录日志记录成功!");
} catch (Exception e) {
log.error("save tenant login log fail:", e);
throw new InternalServerException("保存租户登录日志记录失败", e, e.getMessage());
}
}
/**
* 用户登录记录列表展示
*
* @param pager
* @return
*/
@Override
public GeneralResult<GridBean<LoginRecord>> list(Pager pager) {
GridBean<LoginRecord> gridBean;
try {
List<Param> params = Optional.ofNullable(pager.getParams()).orElse(new ArrayList<>());
Map<String, String> sorter = Optional.ofNullable(pager.getSorter()).orElse(new HashMap<>());
sorter.put("gmt_create", Common.ONE);
int total = loginRecordRepository.loginTimes(params);
List<LoginRecord> list = loginRecordRepository.list(pager);
gridBean = new GridBean<>(pager.getPage(), pager.getRows(), total, list);
return new GeneralResult<>(true, gridBean, "查询成功");
} catch (Exception e) {
log.error("Query user login record list fail:", e);
return new GeneralResult<>(false, "查询失败:" + e.getMessage());
}
}
/**
* 添加收藏
*
* @param serviceId
* @param requestContext
* @return
*/
@Override
@Transactional(rollbackFor = InternalServerException.class)
public Result addFavorite(Long serviceId, RequestContext requestContext) throws InternalServerException {
try {
Favorite favorite = new Favorite(null, Favorite.Category.User, requestContext.getTarget(), serviceId, 0);
favoriteRepository.save(favorite);
return new Result(true, "添加收藏成功");
} catch (Exception e) {
log.error("add favorite failed," + e);
throw new InternalServerException("添加收藏失败", e, e.getMessage());
}
}
/**
* 取消收藏
*
* @param serviceId
* @param requestContext
* @return
*/
@Override
@Transactional(rollbackFor = InternalServerException.class)
public Result cancelFavorite(Long serviceId, RequestContext requestContext) throws InternalServerException {
try {
favoriteRepository.cancelFavorite(serviceId, requestContext.getTarget(),
requestContext.getCatalog().name());
return new Result(true, "取消收藏成功");
} catch (Exception e) {
log.error("add favorite failed," + e);
throw new InternalServerException("取消收藏失败", e, e.getMessage());
}
}
/**
* 获取服务目录
*
* @param requestContext
* @return
*/
@Override
public GeneralResult<List<ServiceMenuBean>> listServiceMenu(RequestContext requestContext) {
try {
// 获取用户角色授权的服务菜单权限
// List<Role> roles = roleRepository.listByUser(requestContext.getTarget());
// Map<String, CloudService> permissionMap = new HashMap<>(8);
// for (Role role : roles) {
// List<CloudService> permissions = roleRepository.listRoleServices(role.getId());
// permissionMap.putAll(permissions.stream().distinct().filter(cloudService ->
// !"vmware.storage.disk".equals(cloudService.getCode())).collect(Collectors.toMap(CloudService::getCode,
// Function.identity())));
// }
// 获取用户所属租户的服务菜单权限
List<CloudServiceBean> allServices = cloudServiceBeanRepository
.getFavoriteServices(requestContext.getTenant(), RequestContext.Catalog.Tenant.name());
// ArrayList<CloudService> cloudServices = new ArrayList<>(permissionMap.values());
// List<CloudServiceBean> allServices =
// cloudServices.stream().map(CloudServiceBean::new).collect(Collectors.toList());
// 创建集合用于接收递归查询的相关权限
HashMap<String, List<CloudServiceBean>> serviceMenu = new HashMap<>();
// 获取用户收藏了的服务菜单权限
List<CloudServiceBean> favoriteServices =
cloudServiceBeanRepository.getFavoriteServices(requestContext.getTarget(), Catalog.User.name());
List<Long> serviceIds = allServices.stream().map(CloudServiceBean::getId).collect(Collectors.toList());
// 获取授权的服务对应的菜单权限
List<Permission> servicePermissions = permissionRepository.getServicesPermissions(serviceIds);
// 查询服务编码集合
List<String> permissionCodes =
allServices.stream().map(CloudServiceBean::getCode).collect(Collectors.toList());
// List<String> permissionCodes = new ArrayList<>(permissionMap.keySet());
HashMap<String, List<Permission>> servicePermissionMap = new HashMap<>(8);
for (String code : permissionCodes) {
ArrayList<Permission> permissions = new ArrayList<>();
for (Permission servicePermission : servicePermissions) {
if (servicePermission.getServiceCodes().contains(code)) {
permissions.add(servicePermission);
}
}
servicePermissionMap.put(code, permissions);
}
for (CloudServiceBean cloudServiceBean : allServices) {
ArrayList<CloudServiceBean> cloudServiceBeans = new ArrayList<>();
List<Permission> permissions = servicePermissionMap.get(cloudServiceBean.getCode());
if (permissions != null && permissions.size() > 0) {
Permission permission =
permissions.stream().filter(permit -> "isServiceMenu".equals(permit.getProps())).findAny()
.orElse(permissions.get(0));
cloudServiceBean.setPath(permission.getPath());
}
if (favoriteServices.isEmpty()) {
cloudServiceBean.setFavorite(false);
}
for (CloudServiceBean service : favoriteServices) {
// 用户授权了该服务则设置收藏状态为true
if (cloudServiceBean.getName().equals(service.getName())) {
cloudServiceBean.setFavorite(true);
break;
} else {
cloudServiceBean.setFavorite(false);
}
}
// 按服务类型分组收集服务菜单权限
if (!serviceMenu.containsKey(cloudServiceBean.getCatalogName())) {
// 不包含的服务类型就直接添加到集合中
cloudServiceBeans.add(cloudServiceBean);
serviceMenu.put(cloudServiceBean.getCatalogName(), cloudServiceBeans);
} else {
// 存在的服务类型则获取该服务的菜单权限后再添加到原有的服务菜单权限中
List<CloudServiceBean> serviceMenus = serviceMenu.get(cloudServiceBean.getCatalogName());
serviceMenus.add(cloudServiceBean);
serviceMenu.put(cloudServiceBean.getCatalogName(), serviceMenus);
}
}
ArrayList<ServiceMenuBean> serviceMenus = new ArrayList<>();
ArrayList<String> categorys = Lists.newArrayList("计算", "存储", "网络", "数据库", "中间件", "运维", "编排", "监控");
for (String key : categorys) {
List<CloudServiceBean> serviceBeanList = serviceMenu.get(key);
if (null != serviceBeanList && !serviceBeanList.isEmpty()) {
serviceMenus.add(new ServiceMenuBean(key, serviceBeanList));
}
}
return new GeneralResult<>(true, serviceMenus, "查询服务目录成功");
} catch (Exception e) {
log.error("get service menus error,", e);
return new GeneralResult<>(false, "查询失败:" + e.getMessage());
}
}
/**
* 获取收藏夹
*
* @param requestContext
* @return
*/
@Override
public GeneralResult<List<CloudServiceBean>> listFavorite(RequestContext requestContext) {
try {
// 获取用户收藏的服务菜单
List<CloudServiceBean> favoriteServices =
cloudServiceBeanRepository.getFavoriteServices(requestContext.getTarget(), Catalog.User.name());
ArrayList<CloudServiceBean> favorites = new ArrayList<>();
List<Long> serviceIds = favoriteServices.stream().map(CloudServiceBean::getId).collect(Collectors.toList());
// 获取用户收藏的服务对应的菜单权限
List<Permission> servicePermissions = permissionRepository.getServicesPermissions(serviceIds);
// 查询服务编码集合
List<String> permissionCodes =
favoriteServices.stream().map(CloudServiceBean::getCode).collect(Collectors.toList());
HashMap<String, List<Permission>> servicePermissionMap = new HashMap<>();
for (String code : permissionCodes) {
ArrayList<Permission> permissions = new ArrayList<>();
for (Permission servicePermission : servicePermissions) {
if (servicePermission.getServiceCodes().contains(code)) {
permissions.add(servicePermission);
}
}
servicePermissionMap.put(code, permissions);
}
for (CloudServiceBean cloudServiceBean : favoriteServices) {
List<Permission> permissions = servicePermissionMap.get(cloudServiceBean.getCode());
if (permissions != null && permissions.size() > 0) {
// 获取当前服务对应的菜单权限,并给对应的服务目录对象设置路由
Permission permission =
permissions.stream().filter(permit -> "isServiceMenu".equals(permit.getProps())).findAny()
.orElse(permissions.get(0));
cloudServiceBean.setPath(permission.getPath());
}
cloudServiceBean.setFavorite(true);
// 设置排序优先级
cloudServiceBean.setPriority(cloudServiceBean.getPriority());
favorites.add(cloudServiceBean);
}
favorites.sort(new FavoriteComparator());
return new GeneralResult<>(true, favorites, "查询服务收藏夹成功");
} catch (Exception e) {
log.error("get favorite error," + e);
return new GeneralResult<>(false, "查询失败:" + e.getMessage());
}
}
/**
* 修改收藏夹排序
*
* @param priorityModels
* @param requestContext
* @return
*/
@Override
@Transactional(rollbackFor = InternalServerException.class)
public Result changePriority(List<PriorityModel> priorityModels, RequestContext requestContext)
throws InternalServerException {
try {
for (PriorityModel priorityModel : priorityModels) {
favoriteRepository.changePriority(priorityModel.getId(), priorityModel.getPriority(),
requestContext.getTarget());
}
return new Result(true, "修改收藏夹排序成功");
} catch (Exception e) {
log.error("change favorite priority error," + e);
throw new InternalServerException("修改收藏夹排序失败", e, e.getMessage());
}
}
/**
* 返回账号相关登录所需信息
*
* @param account
* @return
*/
@Override
public GeneralResult<Map<String, Object>> tokenLogin(String account) {
// 判断用户是否存在
User user;
try {
user = userRepository.getByAccount(account);
} catch (Exception e) {
log.error("Get User fail by account:", e);
return new GeneralResult<>(false, "该账号存在问题,校验失败");
}
if (null == user) {
log.warn("User is null");
return new GeneralResult<>(false, "该账号存在问题,校验失败");
}
if (user.getStatus().equals(BaseStatus.ABNORMAL.name())) {
return new GeneralResult<>(false, "该账号用户已被冻结,用户无法登录");
}
// 查询随机数
AccountSecurity security;
try {
security = securityRepository.getByTarget(user.getId(), Catalog.User);
} catch (Exception e) {
log.error("Query Random fail:", e);
return new GeneralResult<>(false, "该账号存在问题,校验失败");
}
if (null == security) {
log.warn("Security is null");
return new GeneralResult<>(false, "该账号存在问题,校验失败");
}
Map<String, Object> map = MapTools.simpleMap(Common.USER, user);
map.put(Common.API_KEY, security.getApiKey());
map.put(Common.SEC_KEY, security.getSecKey());
map.put("accountCategory", Catalog.User.name());
return new GeneralResult<>(true, map, "用户跳转成功");
}
@Override
public Result exist(String account) {
try {
User user = userRepository.getByAccount(account);
return user == null ? new Result(true, "账号可以使用") : new Result(false, "账号已经存在");
} catch (Exception e) {
log.error("query user by account error,", e);
return new Result(false, "查询失败:" + e.getMessage());
}
}
@Override
public GeneralResult<List<Project>> projects(Long id) {
try {
User user = userRepository.query(id);
Assert.notNull(user, "用户不存在");
List<Project> projects = projectRepository.listUserProject(id);
return new GeneralResult<>(true, projects, "查询成功");
} catch (Exception e) {
log.error("List user project fail:", e);
return new GeneralResult<>(false, "查询失败:" + e.getMessage());
}
}
@Override
public Result importTemp(String name, HttpServletResponse response) {
// 下拉列表数据
List<String> departmentsName = new ArrayList<>();
List<String> tenantsName = new ArrayList<>();
ArrayList<String> sex = new ArrayList<>();
ArrayList<String> IsManager = new ArrayList<>();
try {
// 部门数据
departmentsName =
departmentRepository.listAll().stream().map(Department::getName).collect(Collectors.toList());
// 租户数据
tenantsName = tenantRepository.list().stream().map(Tenant::getName).collect(Collectors.toList());
} catch (Exception e) {
log.error("获取租户或部门数据异常", e);
}
sex.add("男");
sex.add("女");
IsManager.add("管理用户");
IsManager.add("普通用户");
// 校验数据 map: k 表示列 indexv 表示下拉列表数据
HashMap<Integer, List<String>> map = new HashMap<>(8);
map.put(4, sex);
if (tenantsName.size() > 0) {
map.put(5, tenantsName);
}
if (departmentsName.size() > 0) {
map.put(10, departmentsName);
}
map.put(11, IsManager);
CellWriteHandler cellWriteHandler = ExportUtil.getCellWriteHandler(map);
boolean res =
exportExcel("用户列表模板", "导出模板", response, new ArrayList<>(), ImportUserTemplate.class, cellWriteHandler);
return res ? new Result(true, "用户模板下载成功") : new Result(false, "用户模板下载失败");
}
@Override
public Result importData(MultipartFile multipartFile, Long tenantId, RequestContext requestContext) {
try {
String originalFilename = multipartFile.getOriginalFilename();
Assert.notNull(originalFilename, "文件名不能为空");
String[] checkedHead = new String[]{"用户名称", "登录账号", "钉钉账号", "微信账号", "用户性别", "所属租户", "电子邮箱", "联系电话", "用户工号",
"公司名称", "所属组织", "是否为管理员", "用户描述"};
Map<String, Object> paramMap = MapTools.simpleMap("requestContext", requestContext);
paramMap.put("tenantId", tenantId);
AnalysisEventListener<ImportUserTemplate> analysisEventListener =
ImportExcelUtil.getListener(this.batchInsert(), 1000, checkedHead, paramMap);
EasyExcel.read(multipartFile.getInputStream(), ImportUserTemplate.class, analysisEventListener).sheet()
.doRead();
return ImportExcelUtil.getResult();
} catch (Exception e) {
log.error("用户导入异常", e);
return ImportExcelUtil.getResult();
}
}
private BiFunction<List<ImportUserTemplate>, Map<String, Object>, Result> batchInsert() {
return (impUserTemp, paramsMap) -> {
StringBuilder errorMsg = new StringBuilder();
ArrayList<User> users = new ArrayList<>();
RequestContext requestContext = (RequestContext) paramsMap.get("requestContext");
Long tenantId = (Long) paramsMap.get("tenantId");
if (!impUserTemp.isEmpty()) {
for (ImportUserTemplate userTemplate : impUserTemp) {
// 防止导入空行
if (userTemplate.getAccount() == null && userTemplate.getName() == null
&& userTemplate.getMobile() == null) {
continue;
}
User user = new User();
user.setName(userTemplate.getName());
user.setAccount(userTemplate.getAccount());
user.setEmail(userTemplate.getEmail());
user.setIsManager("管理用户".equals(userTemplate.getIsManager()));
if (tenantId == null || tenantId == 0L) {
user.setTenantName(userTemplate.getTenantName());
}
user.setCompany(userTemplate.getCompany());
user.setDepartmentName(userTemplate.getDepartmentName());
user.setDingtalk(userTemplate.getDingtalk());
user.setJobNumber(userTemplate.getJobNumber());
user.setMobile(userTemplate.getMobile());
user.setRemark(userTemplate.getRemark());
user.setWechat(userTemplate.getWechat());
if (userTemplate.getSex() == null) {
user.setSex(null);
} else {
user.setSex("男".equals(userTemplate.getSex()));
}
users.add(user);
}
}
try {
if (null != tenantId && 0L != tenantId) {
Tenant tenant = tenantRepository.query(tenantId);
for (User user : users) {
user.setTenantId(tenantId);
user.setDepartId(tenant.getDepartId());
user.setTenantName(tenant.getName());
}
} else {
for (User user : users) {
user.setTenantId(0L);
}
}
int successNum = 0;
int errorNumber = 0;
List<String> existNames = userRepository.list().stream().map(User::getName).toList();
List<String> existAccounts = userRepository.list().stream().map(User::getAccount).toList();
Map<String, Tenant> tenantMap =
tenantRepository.list().stream().collect(Collectors.toMap(Tenant::getName, Function.identity()));
Map<String, Department> departmentMap = departmentRepository.listAll().stream()
.collect(Collectors.toMap(Department::getName, Function.identity()));
ListIterator<User> listIterator = users.listIterator();
// 邮箱格式
String EMAIL_REGEX = "^[\\w-_\\.+]*[\\w-_\\.]\\@([\\w]+\\.)+[\\w]+[\\w]$";
while (listIterator.hasNext()) {
User user = listIterator.next();
if (user.getName() == null || user.getAccount() == null || user.getIsManager() == null
|| user.getEmail() == null || user.getSex() == null || user.getMobile() == null) {
errorNumber++;
listIterator.remove();
log.error("{} 用户名称,登录账号、是否为管理员、电子邮箱、用户性别、联系电话,存在空值", user.getName());
errorMsg.append(user.getName()).append(":用户名称,登录账号、是否为管理员、电子邮箱、用户性别、联系电话,存在空值");
continue;
}
String name = user.getName();
if (existNames.contains(name)) {
errorNumber++;
listIterator.remove();
log.error("user {} has existed", name);
errorMsg.append(name).append(":用户名已存在");
continue;
}
String account = user.getAccount();
if (existAccounts.contains(account)) {
errorNumber++;
listIterator.remove();
log.error("user account {} has existed", account);
errorMsg.append(account).append(":账号已存在");
continue;
}
if (user.getEmail() != null && !user.getEmail().matches(EMAIL_REGEX)) {
errorNumber++;
log.error("{}邮箱格式错误", user.getName());
errorMsg.append(user.getName()).append(":邮箱格式错误");
listIterator.remove();
continue;
}
if (!StringUtils.hasText(account) || !StringUtils.hasText(name)) {
errorNumber++;
listIterator.remove();
log.error("user account or name can't be empty.");
errorMsg.append("用户名、账号不能为空");
continue;
}
if (StringUtils.hasText(user.getTenantName())) {
if (!tenantMap.containsKey(user.getTenantName())) {
errorNumber++;
listIterator.remove();
errorMsg.append(user.getName()).append(":租户不存在");
log.error("user {} 's tenant {} don't exist", user.getName(), user.getTenantName());
} else {
Tenant tenant = tenantMap.get(user.getTenantName());
user.setTenantId(tenant.getId());
user.setDepartId(tenant.getDepartId());
}
} else {
if (!departmentMap.containsKey(user.getDepartmentName()) && user.getDepartmentName() != null) {
errorNumber++;
listIterator.remove();
errorMsg.append(user.getName()).append(":部门不存在");
log.error("user {} 's department {} don't exist", user.getName(), user.getTenantName());
}
// 设置用户部门id
if (departmentMap.get(user.getDepartmentName()) != null) {
user.setDepartId(departmentMap.get(user.getDepartmentName()).getId());
}
}
}
List<Result> list = new ArrayList<>();
for (User user : users) {
Future<Result> future = taskExecutor.submit(() -> this.createUser(user, requestContext));
Result result = future.get();
list.add(result);
}
for (Result res : list) {
if (res.isSuccess()) {
successNum++;
} else {
errorMsg.append(res.getMessage());
}
}
if (successNum == users.size() && errorNumber == 0) {
return new Result(true, "导入用户信息成功");
} else if (successNum > 0) {
return new Result(true, successNum + "条用户信息导入成功," + (users.size() - successNum + errorNumber)
+ "条用户信息导入异常 " + errorMsg);
} else {
return new Result(true,
successNum + "条用户信息导入成功," + (users.size() - successNum + errorNumber) + "条用户信息导入异常" + errorMsg);
}
} catch (Exception e) {
log.error("用户导入异常", e);
return new Result(false, "用户信息导入异常" + errorMsg);
}
};
}
private GeneralResult<List<User>> readExcel(Workbook wb, Long tenantId) {
Sheet sheet = wb.getSheetAt(0);
List<User> users = new ArrayList<>();
for (int rowNum = 1; rowNum <= sheet.getLastRowNum(); rowNum++) {
Row row = sheet.getRow(rowNum);
User user = new User();
Cell name = row.getCell(0);
user.setName(getCellStringValue(name));
Cell account = row.getCell(1);
user.setAccount(getCellStringValue(account));
Cell sex = row.getCell(4);
String sexValue = getCellStringValue(sex);
user.setSex(sexValue == null ? null : "男".equals(sexValue));
if (null == tenantId || 0L == tenantId) {
Cell dingtalk = row.getCell(2);
user.setDingtalk(getCellStringValue(dingtalk));
Cell wechat = row.getCell(3);
user.setWechat(getCellStringValue(wechat));
Cell tenant = row.getCell(5);
user.setTenantName(getCellStringValue(tenant));
Cell email = row.getCell(6);
user.setEmail(getCellStringValue(email));
Cell mobile = row.getCell(7);
CellType cellTypeEnum = mobile.getCellTypeEnum();
if (!cellTypeEnum.name().equals(CellType.NUMERIC.name())) {
return new GeneralResult<>(false, null, "手机号列仅限数字格式");
}
user.setMobile(getCellStringValue(mobile));
Cell jobNumber = row.getCell(8);
user.setJobNumber(getCellStringValue(jobNumber));
Cell company = row.getCell(9);
user.setCompany(getCellStringValue(company));
Cell manager = row.getCell(10);
user.setIsManager("是".equals(getCellStringValue(manager)));
Cell remark = row.getCell(11);
user.setRemark(getCellStringValue(remark));
} else {
Cell dingtalk = row.getCell(2);
user.setDingtalk(getCellStringValue(dingtalk));
Cell wechat = row.getCell(3);
user.setWechat(getCellStringValue(wechat));
Cell email = row.getCell(5);
user.setEmail(getCellStringValue(email));
Cell mobile = row.getCell(6);
user.setMobile(getCellStringValue(mobile));
Cell jobNumber = row.getCell(7);
user.setJobNumber(getCellStringValue(jobNumber));
Cell company = row.getCell(8);
user.setCompany(getCellStringValue(company));
Cell manager = row.getCell(9);
user.setIsManager("是".equals(getCellStringValue(manager)));
Cell remark = row.getCell(10);
user.setRemark(getCellStringValue(remark));
}
users.add(user);
}
return new GeneralResult<>(true, users, "");
}
private Result createUser(User user, RequestContext requestContext) {
StringBuilder errMsg = new StringBuilder();
try {
user.setCreatorId(requestContext.getTarget());
// 初始化密码
String salt = UUID.randomUUID().toString();
Encryptor encryptor = new SHAEncryptor();
User existUser = userRepository.getByAccount(user.getAccount());
if (existUser != null) {
errMsg.append(existUser.getName()).append("该账号已存在");
throw new IllegalArgumentException("该账号已存在");
}
if (StringUtils.hasText(user.getEmail())) {
User existEmailUser = userRepository.getByEmail(user.getEmail());
if (null != existEmailUser) {
errMsg.append(existEmailUser.getName()).append("该邮箱已被注册");
throw new IllegalArgumentException("该邮箱已被注册");
}
}
String password = encryptor.encrypt("Aa123456", salt);
user.setPassword(password);
// 关键信息去空
user.setAccount(user.getAccount().trim());
user.setName(user.getName().trim());
user.setStatus(BaseStatus.NORMAL.name());
user.setLoginStatus(false);
user.setLastPwdModifyDate(new Date());
user.setOrigin("SYSTEM");
userRepository.save(user);
String account = user.getAccount();
User cacheUser = userRepository.getByAccount(account);
redisTemplate.opsForValue().set(Catalog.User.name() + "_" + cacheUser.getId(), account);
redisTemplate.opsForValue().set(Catalog.User.name() + "_Name_" + cacheUser.getId(), cacheUser.getName());
// 构建用户随机数对象
AccountSecurity security = new AccountSecurity();
String data = user.getAccount() + System.currentTimeMillis();
String apiKey = encryptor.encrypt(data, Common.API_KEY);
String secKey = encryptor.encrypt(data, Common.SEC_KEY);
security.setTargetId(user.getId());
security.setCategory(AccountSecurity.Category.User);
security.setSalt(salt);
security.setApiKey(apiKey);
security.setSecKey(secKey);
security.setTenantId(user.getTenantId());
boolean success = securityRepository.baseSave(security);
if (!success) {
callback(user.getId(), requestContext);
}
return new Result(true, "");
} catch (Exception e) {
log.error("create user fail:", e);
this.callback(user.getId(), requestContext);
return new Result(false, errMsg.toString());
}
}
private void callback(Long targetId, RequestContext context) {
try {
User user = userRepository.query(targetId);
if (user != null) {
userRepository.delete(targetId, context.getTarget());
redisTemplate.delete(RequestContext.Catalog.User.name() + "_" + user.getId());
redisTemplate.delete(RequestContext.Catalog.User.name() + "_Name_" + user.getId());
}
securityRepository.delete(targetId, RequestContext.Catalog.User);
} catch (Exception e) {
log.error("call back error:{}", e.getMessage());
}
}
@Override
public Result export(List<Param> paramList, RequestContext requestContext, HttpServletResponse response) {
try {
Map<String, String> sorter = new HashMap<>(8);
if (!Catalog.Manager.equals(requestContext.getCatalog())) {
Map<String, Object> tenantMap = MapTools.simpleMap("tenantId", requestContext.getTenant());
Param param = new Param(tenantMap, Sign.EQ);
paramList.add(param);
}
sorter.put("gmtCreate", Common.ONE);
Long roleId = null;
Iterator<Param> paramIterator = paramList.iterator();
// 有参数时判断是否有租户id
if (paramIterator.hasNext()) {
Param next = paramIterator.next();
Map<String, Object> paramMap = next.getParam();
if (paramMap.containsKey("roleId")) {
roleId = Long.valueOf(paramMap.get("roleId").toString());
paramMap.remove("roleId");
}
}
List<User> users = userRepository.list(1, Integer.MAX_VALUE, paramList, sorter, roleId);
for (User user : users) {
Department department = departmentRepository.query(user.getDepartId());
if (department != null) {
user.setDepartmentName(department.getName());
}
}
ArrayList<ImportUserTemplate> list = new ArrayList<>();
for (User user : users) {
ImportUserTemplate userTemplate = new ImportUserTemplate();
userTemplate.setAccount(user.getAccount());
userTemplate.setName(user.getName());
userTemplate.setDingtalk(user.getDingtalk());
userTemplate.setWechat(user.getWechat());
userTemplate.setSex(user.getSex() ? "男" : "女");
userTemplate.setTenantName(user.getTenantName());
userTemplate.setEmail(user.getEmail());
userTemplate.setMobile(user.getMobile());
userTemplate.setJobNumber(user.getJobNumber());
userTemplate.setCompany(user.getCompany());
userTemplate.setDepartmentName(user.getDepartmentName());
userTemplate.setRemark(user.getRemark());
userTemplate.setIsManager(null != user.getIsManager() && user.getIsManager() ? "管理用户" : "普通用户");
list.add(userTemplate);
}
boolean exportExcel = exportExcel("用户列表" + System.currentTimeMillis(), "用户列表", response, list,
ImportUserTemplate.class, null);
return exportExcel ? new Result(true, "用户导出成功") : new Result(false, "用户导出失败");
} catch (Exception e) {
log.error("create user work book failed:", e);
return new Result(false, "用户导出异常");
}
}
@Override
public Result unBindTenants(Long id, RequestContext requestContext) {
String path = User.class.getSimpleName() + "_" + id;
try (AutoCloseLock lock = lockFactory.getACLock(path)) {
Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
User user = userRepository.query(id);
Assert.notNull(user, "用户信息不存在");
user.setTenantId(0L);
user.setMenderId(requestContext.getTarget());
userRepository.update(user);
return new Result(true, "操作成功");
} catch (Exception e) {
log.error("user unbind tenant failed:", e);
return new Result(false, "操作失败");
}
}
@Override
public GeneralResult<?> checkPassword(RequestContext requestContext, String password) {
User user;
AccountSecurity security;
try {
user = userRepository.query(requestContext.getTarget());
security = securityRepository.getByTarget(user.getId(), Catalog.User);
// 对前端传过来的密码进行解密
Encryptor encryptor = new AESEncryptor();
password = encryptor.decrypt(password.trim(), null);
if (!StringUtils.hasText(password)) {
return new GeneralResult<>(false, "账号或密码错误");
}
// 密码加密
encryptor = new SHAEncryptor();
String encryptString = encryptor.encrypt(password, security.getSalt());
if (null == encryptString || !encryptString.equals(user.getPassword())) {
log.warn("Wrong user account or password");
return new GeneralResult<>(false, "账号或密码错误");
}
} catch (Exception e) {
log.error("用户密码解密异常{}", e.getMessage());
return new GeneralResult<>(false, "密码错误");
}
return new GeneralResult<>(true, "密码正确");
}
}