🏗️ 初始化逻辑调整

master
smallbun 2024-12-16 01:03:56 +08:00
parent f044f4e2ad
commit 2c4a946cda
6 changed files with 363 additions and 359 deletions

View File

@ -22,31 +22,24 @@ import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.util.Locale; import java.util.Locale;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.TimeUnit;
import org.redisson.api.RLock; import org.apache.commons.io.FileUtils;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.AlternativeJdkIdGenerator; import org.springframework.util.AlternativeJdkIdGenerator;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import cn.topiam.employee.common.entity.account.OrganizationMemberEntity;
import cn.topiam.employee.common.entity.setting.AdministratorEntity; import cn.topiam.employee.common.entity.setting.AdministratorEntity;
import cn.topiam.employee.common.enums.UserStatus; import cn.topiam.employee.common.enums.UserStatus;
import cn.topiam.employee.common.repository.account.OrganizationMemberRepository;
import cn.topiam.employee.common.repository.setting.AdministratorRepository; import cn.topiam.employee.common.repository.setting.AdministratorRepository;
import cn.topiam.employee.support.init.Initializer; import cn.topiam.employee.support.config.AbstractSystemInitializer;
import cn.topiam.employee.support.trace.TraceUtils; import cn.topiam.employee.support.config.InitializationException;
import static cn.topiam.employee.support.constant.EiamConstants.DEFAULT_ADMIN_USERNAME; import static cn.topiam.employee.support.constant.EiamConstants.DEFAULT_ADMIN_USERNAME;
import static cn.topiam.employee.support.constant.EiamConstants.TOPIAM_INIT_AUTHENTICATION; import static cn.topiam.employee.support.constant.EiamConstants.ROOT_NODE;
import static cn.topiam.employee.support.lock.LockAspect.getTopiamLockKeyPrefix;
import static cn.topiam.employee.support.util.CreateFileUtil.createFile;
/** /**
* DefaultAdministratorInitialize * DefaultAdministratorInitialize
@ -54,9 +47,8 @@ import static cn.topiam.employee.support.util.CreateFileUtil.createFile;
* @author TopIAM * @author TopIAM
* Created by support@topiam.cn on 2022/11/26 21:44 * Created by support@topiam.cn on 2022/11/26 21:44
*/ */
@Order(2)
@Component @Component
public class DefaultAdministratorInitializer implements Initializer { public class DefaultAdministratorInitializer extends AbstractSystemInitializer {
private final Logger logger = LoggerFactory private final Logger logger = LoggerFactory
.getLogger(DefaultAdministratorInitializer.class); .getLogger(DefaultAdministratorInitializer.class);
@ -68,48 +60,43 @@ public class DefaultAdministratorInitializer implements Initializer {
private static final String INITIAL_PASSWORD_DEFAULT = "topiam.cn"; private static final String INITIAL_PASSWORD_DEFAULT = "topiam.cn";
@Override @Override
@Transactional(rollbackFor = Exception.class) public void init() throws InitializationException {
public void execute(ApplicationContext applicationContext) {
//@formatter:off
String traceId = idGenerator.generateId().toString();
TraceUtils.put(traceId);
RLock lock = redissonClient.getLock(getTopiamLockKeyPrefix());
boolean tryLock = false;
try { try {
SecurityContextHolder.getContext().setAuthentication(TOPIAM_INIT_AUTHENTICATION); Optional<AdministratorEntity> optional = administratorRepository
tryLock = lock.tryLock(1, TimeUnit.SECONDS); .findByUsername(DEFAULT_ADMIN_USERNAME);
if (tryLock){
Optional<AdministratorEntity> optional = administratorRepository.findByUsername(DEFAULT_ADMIN_USERNAME);
if (optional.isEmpty()) { if (optional.isEmpty()) {
String initPassword; String initPassword;
String initPasswordFileTips; String initPasswordFileTips;
String passwordType = System.getProperty(INITIAL_PASSWORD_TYPE_NAME); String passwordType = System.getProperty(INITIAL_PASSWORD_TYPE_NAME);
if (StringUtils.hasText(passwordType) && "generate".equals(passwordType)) { if (StringUtils.hasText(passwordType) && "generate".equals(passwordType)) {
initPassword = idGenerator.generateId().toString().replace("-", "").toLowerCase(Locale.ENGLISH); initPassword = idGenerator.generateId().toString().replace("-", "")
} .toLowerCase(Locale.ENGLISH);
else { } else {
String passwordInitial = System.getProperty(INITIAL_PASSWORD_VALUE_NAME); String passwordInitial = System.getProperty(INITIAL_PASSWORD_VALUE_NAME);
if (StringUtils.hasText(passwordInitial)) { if (StringUtils.hasText(passwordInitial)) {
initPassword = passwordInitial; initPassword = passwordInitial;
} } else {
else {
initPassword = INITIAL_PASSWORD_DEFAULT; initPassword = INITIAL_PASSWORD_DEFAULT;
} }
} }
String initialAdminPasswordFilePath = getInitialAdminPasswordFilePath();createFile(initialAdminPasswordFilePath); String initialAdminPasswordFilePath = getInitialAdminPasswordFilePath();
BufferedWriter stream = new BufferedWriter(new FileWriter(initialAdminPasswordFilePath)); FileUtils.writeStringToFile(new File(initialAdminPasswordFilePath), initPassword,
"UTF-8");
BufferedWriter stream = new BufferedWriter(
new FileWriter(initialAdminPasswordFilePath));
initPasswordFileTips = "This may also be found at: " + initialAdminPasswordFilePath; initPasswordFileTips = "This may also be found at: " + initialAdminPasswordFilePath;
//清空 //清空
stream.write(initPassword); stream.write(initPassword);
stream.flush(); stream.flush();
stream.close(); stream.close();
logger.info(""" logger.info(
"""
************************************************************* *************************************************************
************************************************************* *************************************************************
************************************************************* *************************************************************
TOPIAM console initial setup is required. An admin user has been created and a initialize password. TOPIAM console initial setup is required. An admin administrator has been created and a initialize password.
Please use the following password to proceed to installation: Please use the following password to proceed to installation:
%s %s
@ -119,42 +106,26 @@ public class DefaultAdministratorInitializer implements Initializer {
************************************************************* *************************************************************
************************************************************* *************************************************************
""".formatted(initPassword, initPasswordFileTips)); """
.formatted(initPassword, initPasswordFileTips));
//保存管理员 //保存管理员
saveInitAdministrator(DEFAULT_ADMIN_USERNAME, initPassword);
}
}
} catch (Exception exception) {
int exitCode = SpringApplication.exit(applicationContext,
() -> 0);
System.exit(exitCode);
} finally {
if (tryLock && lock.isLocked()) {
lock.unlock();
}
TraceUtils.remove();
SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());
}
//@formatter:on
}
/**
*
*
* @param username {@link String}
* @param password {@link String}
*/
@Transactional(rollbackFor = Exception.class)
public void saveInitAdministrator(String username, String password) {
AdministratorEntity administrator = new AdministratorEntity(); AdministratorEntity administrator = new AdministratorEntity();
administrator.setUsername(username); administrator.setUsername(DEFAULT_ADMIN_USERNAME);
administrator.setPassword(passwordEncoder.encode(password)); administrator.setFullName("管理员");
administrator.setPassword(passwordEncoder.encode(initPassword));
administrator.setStatus(UserStatus.ENABLED); administrator.setStatus(UserStatus.ENABLED);
administrator.setNeedChangePassword(true); administrator.setNeedChangePassword(true);
administrator.setRemark( administrator.setRemark(
"This administrator user is automatically created during system initialization."); "This administrator is automatically created during system initialization.");
administratorRepository.save(administrator); administratorRepository.save(administrator);
OrganizationMemberEntity member = new OrganizationMemberEntity();
member.setOrgId(ROOT_NODE);
member.setUserId(administrator.getId());
organizationMemberRepository.save(member);
}
} catch (Exception e) {
throw new InitializationException(e);
}
} }
public static String addSeparator(String dir) { public static String addSeparator(String dir) {
@ -175,20 +146,24 @@ public class DefaultAdministratorInitializer implements Initializer {
return path + "initialAdminPassword"; return path + "initialAdminPassword";
} }
@Override
public int getOrder() {
return 3;
}
private final AlternativeJdkIdGenerator idGenerator = new AlternativeJdkIdGenerator(); private final AlternativeJdkIdGenerator idGenerator = new AlternativeJdkIdGenerator();
private final OrganizationMemberRepository organizationMemberRepository;
private final AdministratorRepository administratorRepository; private final AdministratorRepository administratorRepository;
private final PasswordEncoder passwordEncoder; private final PasswordEncoder passwordEncoder;
private final RedissonClient redissonClient; public DefaultAdministratorInitializer(OrganizationMemberRepository organizationMemberRepository,
AdministratorRepository administratorRepository,
public DefaultAdministratorInitializer(AdministratorRepository administratorRepository, PasswordEncoder passwordEncoder) {
PasswordEncoder passwordEncoder, this.organizationMemberRepository = organizationMemberRepository;
RedissonClient redissonClient) {
this.administratorRepository = administratorRepository; this.administratorRepository = administratorRepository;
this.passwordEncoder = passwordEncoder; this.passwordEncoder = passwordEncoder;
this.redissonClient = redissonClient;
} }
} }

View File

@ -19,26 +19,17 @@ package cn.topiam.employee.console.initializer;
import java.util.Arrays; import java.util.Arrays;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.TimeUnit;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order; import org.springframework.core.annotation.Order;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.AlternativeJdkIdGenerator;
import cn.topiam.employee.common.entity.app.AppGroupEntity; import cn.topiam.employee.common.entity.app.AppGroupEntity;
import cn.topiam.employee.common.enums.app.AppDefaultGroup; import cn.topiam.employee.common.enums.app.AppDefaultGroup;
import cn.topiam.employee.common.enums.app.AppGroupType; import cn.topiam.employee.common.enums.app.AppGroupType;
import cn.topiam.employee.common.repository.app.AppGroupRepository; import cn.topiam.employee.common.repository.app.AppGroupRepository;
import cn.topiam.employee.support.init.Initializer; import cn.topiam.employee.support.config.AbstractSystemInitializer;
import cn.topiam.employee.support.trace.TraceUtils; import cn.topiam.employee.support.config.InitializationException;
import static cn.topiam.employee.support.constant.EiamConstants.TOPIAM_INIT_AUTHENTICATION;
import static cn.topiam.employee.support.lock.LockAspect.getTopiamLockKeyPrefix;
/** /**
* DefaultAppGroupInitialize * DefaultAppGroupInitialize
@ -48,20 +39,12 @@ import static cn.topiam.employee.support.lock.LockAspect.getTopiamLockKeyPrefix;
*/ */
@Order(2) @Order(2)
@Component @Component
public class DefaultAppGroupInitializer implements Initializer { public class DefaultAppGroupInitializer extends AbstractSystemInitializer {
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void execute(ApplicationContext applicationContext) { public void init() throws InitializationException {
//@formatter:off //@formatter:off
String traceId = idGenerator.generateId().toString();
TraceUtils.put(traceId);
RLock lock = redissonClient.getLock(getTopiamLockKeyPrefix());
boolean tryLock = false;
try {
SecurityContextHolder.getContext().setAuthentication(TOPIAM_INIT_AUTHENTICATION);
tryLock = lock.tryLock(1, TimeUnit.SECONDS);
if (tryLock) {
Arrays.stream(AppDefaultGroup.values()).toList().forEach(i -> { Arrays.stream(AppDefaultGroup.values()).toList().forEach(i -> {
Optional<AppGroupEntity> optional = appGroupRepository.findByCode(i.getCode()); Optional<AppGroupEntity> optional = appGroupRepository.findByCode(i.getCode());
if (optional.isEmpty()) { if (optional.isEmpty()) {
@ -74,33 +57,16 @@ public class DefaultAppGroupInitializer implements Initializer {
appGroupRepository.save(appGroup); appGroupRepository.save(appGroup);
} }
}); });
} }
@Override
} catch (Exception exception) { public int getOrder() {
int exitCode = SpringApplication.exit(applicationContext, return 4;
() -> 0);
System.exit(exitCode);
} finally {
if (tryLock && lock.isLocked()) {
lock.unlock();
} }
TraceUtils.remove();
SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());
}
//@formatter:on
}
private final AlternativeJdkIdGenerator idGenerator = new AlternativeJdkIdGenerator();
private final AppGroupRepository appGroupRepository; private final AppGroupRepository appGroupRepository;
private final RedissonClient redissonClient;
public DefaultAppGroupInitializer(AppGroupRepository appGroupRepository, public DefaultAppGroupInitializer(AppGroupRepository appGroupRepository) {
RedissonClient redissonClient) {
this.appGroupRepository = appGroupRepository; this.appGroupRepository = appGroupRepository;
this.redissonClient = redissonClient;
} }
} }

View File

@ -0,0 +1,73 @@
/*
* eiam-console - Employee Identity and Access Management
* Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cn.topiam.employee.console.initializer;
import java.util.Objects;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import cn.topiam.employee.common.entity.setting.SettingEntity;
import cn.topiam.employee.common.repository.setting.SettingRepository;
import cn.topiam.employee.support.config.AbstractSystemInitializer;
import cn.topiam.employee.support.config.InitializationException;
import cn.topiam.employee.support.util.AesUtils;
import static cn.topiam.employee.common.constant.SettingConstants.AES_SECRET;
/**
* EncryptSecretInitializer
*
* @author TopIAM
* Created by support@topiam.cn on 2024/04/04 21:24
*/
@Component
public class EncryptSecretInitializer extends AbstractSystemInitializer {
@Override
@Transactional(rollbackFor = Exception.class)
public void init() throws InitializationException {
SettingEntity optional = settingRepository.findByName(AES_SECRET);
if (Objects.isNull(optional)) {
SettingEntity setting = new SettingEntity();
setting.setName(AES_SECRET);
setting.setValue(AesUtils.generateKey());
setting.setDesc("Project aes secret");
setting.setRemark(
"This aes secret is automatically created during system initialization.");
settingRepository.save(setting);
}
}
@Override
public int getOrder() {
return Integer.MIN_VALUE;
}
/**
* SettingRepository
*/
private final SettingRepository settingRepository;
/**
*
* @param settingRepository {@link SettingRepository}
*/
public EncryptSecretInitializer(SettingRepository settingRepository) {
this.settingRepository = settingRepository;
}
}

View File

@ -0,0 +1,92 @@
/*
* eiam-console - Employee Identity and Access Management
* Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cn.topiam.employee.console.initializer;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import cn.topiam.employee.common.entity.setting.SettingEntity;
import cn.topiam.employee.common.geo.GeoLocationProviderConfig;
import cn.topiam.employee.common.jackjson.encrypt.EncryptionModule;
import cn.topiam.employee.common.repository.setting.SettingRepository;
import cn.topiam.employee.support.config.AbstractSystemInitializer;
import cn.topiam.employee.support.config.InitializationException;
import static cn.topiam.employee.common.geo.ip2region.Ip2regionGeoLocationParserImpl.IP2REGION;
import static cn.topiam.employee.core.setting.GeoIpProviderConstants.IPADDRESS_SETTING_NAME;
/**
* GeoIpProviderInitializer
*
* @author TOPIAM
* Created by support@topiam.cn on 2024/11/3 18:11
*/
@Component
public class GeoIpProviderInitializer extends AbstractSystemInitializer {
private final Logger logger = LoggerFactory.getLogger(GeoIpProviderInitializer.class);
@Override
@Transactional(rollbackFor = Exception.class)
public void init() throws InitializationException {
//@formatter:off
try {
SettingEntity optional = settingRepository.findByName(IPADDRESS_SETTING_NAME);
if (Objects.isNull(optional)) {
logger.info("初始化系统默认IP地址提供商");
SettingEntity setting = new SettingEntity();
setting.setName(IPADDRESS_SETTING_NAME);
ObjectMapper objectMapper = EncryptionModule.deserializerDecrypt();
// 指定序列化输入的类型
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
setting.setValue(objectMapper.writeValueAsString(new GeoLocationProviderConfig(IP2REGION, null)));
setting.setDesc(IP2REGION.getName());
setting.setRemark("The system initializes the default configuration.");
settingRepository.save(setting);
}
} catch (JsonProcessingException e) {
throw new InitializationException(e);
}
//@formatter:on
}
@Override
public int getOrder() {
return 2;
}
/**
* SettingRepository
*/
private final SettingRepository settingRepository;
/**
*
* @param settingRepository {@link SettingRepository}
*/
public GeoIpProviderInitializer(SettingRepository settingRepository) {
this.settingRepository = settingRepository;
}
}

View File

@ -0,0 +1,95 @@
/*
* eiam-console - Employee Identity and Access Management
* Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cn.topiam.employee.console.initializer;
import java.time.LocalDateTime;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import com.google.common.collect.Lists;
import cn.topiam.employee.common.entity.account.OrganizationEntity;
import cn.topiam.employee.common.enums.account.OrganizationType;
import cn.topiam.employee.common.repository.account.OrganizationRepository;
import cn.topiam.employee.support.config.AbstractSystemInitializer;
import cn.topiam.employee.support.config.InitializationException;
import cn.topiam.employee.support.security.util.SecurityUtils;
import static cn.topiam.employee.support.constant.EiamConstants.*;
import static cn.topiam.employee.support.security.userdetails.DataOrigin.INPUT;
/**
* SystemInitializer
*
* @author TopIAM
* Created by support@topiam.cn on 2024/04/04 21:24
*/
@Component
public class RootOrganizationInitializer extends AbstractSystemInitializer {
private final Logger logger = LoggerFactory.getLogger(RootOrganizationInitializer.class);
@Override
@Transactional(rollbackFor = Exception.class)
public void init() throws InitializationException {
//@formatter:off
Optional<OrganizationEntity> optional = organizationRepository.findById(ROOT_NODE);
if (optional.isEmpty()) {
logger.info("初始化父级组织");
OrganizationEntity organization = new OrganizationEntity();
organization.setId(ROOT_NODE);
organization.setName(ROOT_DEPT_NAME);
organization.setCode(ROOT_NODE);
organization.setPath(PATH_SEPARATOR+ROOT_NODE);
organization.setDisplayPath(PATH_SEPARATOR+ROOT_DEPT_NAME);
organization.setDataOrigin(INPUT.getType());
organization.setType(OrganizationType.GROUP);
organization.setLeaf(false);
organization.setEnabled(true);
organization.setOrder(0L);
organization.setCreateBy(SecurityUtils.getCurrentUserName());
organization.setCreateTime(LocalDateTime.now());
organization.setUpdateBy(SecurityUtils.getCurrentUserName());
organization.setUpdateTime(LocalDateTime.now());
organization.setRemark("Root organization");
organizationRepository.batchSave(Lists.newArrayList(organization));
}
//@formatter:on
}
@Override
public int getOrder() {
return 1;
}
/**
* OrganizationRepository
*/
private final OrganizationRepository organizationRepository;
/**
*
* @param organizationRepository {@link OrganizationRepository}
*/
public RootOrganizationInitializer(OrganizationRepository organizationRepository) {
this.organizationRepository = organizationRepository;
}
}

View File

@ -1,197 +0,0 @@
/*
* eiam-core - Employee Identity and Access Management
* Copyright © 2022-Present Jinan Yuanchuang Network Technology Co., Ltd. (support@topiam.cn)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cn.topiam.employee.core.initializer;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.AlternativeJdkIdGenerator;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import cn.topiam.employee.common.entity.account.OrganizationEntity;
import cn.topiam.employee.common.entity.setting.SettingEntity;
import cn.topiam.employee.common.geo.GeoLocationProviderConfig;
import cn.topiam.employee.common.jackjson.encrypt.EncryptionModule;
import cn.topiam.employee.common.repository.account.OrganizationRepository;
import cn.topiam.employee.common.repository.setting.SettingRepository;
import cn.topiam.employee.support.init.Initializer;
import cn.topiam.employee.support.security.util.SecurityUtils;
import cn.topiam.employee.support.trace.TraceUtils;
import cn.topiam.employee.support.util.AesUtils;
import static cn.topiam.employee.common.constant.SettingConstants.AES_SECRET;
import static cn.topiam.employee.common.enums.account.OrganizationType.DEPARTMENT;
import static cn.topiam.employee.common.geo.ip2region.Ip2regionGeoLocationServiceImpl.IP2REGION;
import static cn.topiam.employee.core.setting.GeoIpProviderConstants.IPADDRESS_SETTING_NAME;
import static cn.topiam.employee.support.constant.EiamConstants.*;
import static cn.topiam.employee.support.lock.LockAspect.getTopiamLockKeyPrefix;
import static cn.topiam.employee.support.security.userdetails.DataOrigin.INPUT;
/**
* SystemInitializer
*
* @author TopIAM
* Created by support@topiam.cn on 2024/04/04 21:24
*/
@Component
public class SystemInitializer implements Initializer {
private final Logger logger = LoggerFactory.getLogger(SystemInitializer.class);
@Override
@Transactional(rollbackFor = Exception.class)
public void execute(ApplicationContext applicationContext) {
String traceId = idGenerator.generateId().toString();
TraceUtils.put(traceId);
RLock lock = redissonClient.getLock(getTopiamLockKeyPrefix() + COLON + "system_init");
boolean tryLock = false;
try {
SecurityContextHolder.getContext().setAuthentication(TOPIAM_INIT_AUTHENTICATION);
tryLock = lock.tryLock(1, TimeUnit.SECONDS);
if (tryLock) {
//init 加密秘钥
initEncryptSecret();
//init IP 提供商
initIpProvider();
//初始化组织机构
initRootOrganization();
}
} catch (Exception e) {
int exitCode = SpringApplication.exit(applicationContext, () -> 0);
System.exit(exitCode);
} finally {
if (tryLock && lock.isLocked()) {
lock.unlock();
}
TraceUtils.remove();
SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());
}
}
/**
*
*/
private void initEncryptSecret() {
SettingEntity optional = settingRepository.findByName(AES_SECRET);
if (Objects.isNull(optional)) {
SettingEntity setting = new SettingEntity();
setting.setName(AES_SECRET);
setting.setValue(AesUtils.generateKey());
setting.setDesc("Project aes secret");
setting.setRemark(
"This aes secret is automatically created during system initialization.");
settingRepository.save(setting);
}
}
/**
* IP
*
* @throws JsonProcessingException JsonProcessingException
*/
private void initIpProvider() throws JsonProcessingException {
//@formatter:off
SettingEntity optional = settingRepository.findByName(IPADDRESS_SETTING_NAME);
if (Objects.isNull(optional)) {
logger.info("初始化系统默认IP地址提供商");
SettingEntity setting = new SettingEntity();
setting.setName(IPADDRESS_SETTING_NAME);
ObjectMapper objectMapper = EncryptionModule.deserializerDecrypt();
// 指定序列化输入的类型
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
setting.setValue(objectMapper.writeValueAsString(new GeoLocationProviderConfig(IP2REGION, null)));
setting.setDesc(IP2REGION.getName());
setting.setRemark("The system initializes the default configuration.");
settingRepository.save(setting);
}
//@formatter:on
}
/**
*
*/
private void initRootOrganization() {
//@formatter:off
Optional<OrganizationEntity> optional = organizationRepository.findById(ROOT_NODE);
if (optional.isEmpty()) {
logger.info("初始化父级组织");
OrganizationEntity organization = new OrganizationEntity();
organization.setId(ROOT_NODE);
organization.setName(ROOT_DEPT_NAME);
organization.setCode(ROOT_NODE);
organization.setPath(PATH_SEPARATOR+ROOT_NODE);
organization.setDisplayPath(PATH_SEPARATOR+ROOT_DEPT_NAME);
organization.setType(DEPARTMENT);
organization.setDataOrigin(INPUT.getType());
organization.setLeaf(false);
organization.setEnabled(true);
organization.setOrder(0L);
organization.setCreateBy(SecurityUtils.getCurrentUserName());
organization.setCreateTime(LocalDateTime.now());
organization.setUpdateBy(SecurityUtils.getCurrentUserName());
organization.setUpdateTime(LocalDateTime.now());
organization.setRemark("Root organization");
organizationRepository.batchSave(Lists.newArrayList(organization));
}
//@formatter:on
}
private final AlternativeJdkIdGenerator idGenerator = new AlternativeJdkIdGenerator();
/**
* RedissonClient
*/
private final RedissonClient redissonClient;
/**
* SettingRepository
*/
private final SettingRepository settingRepository;
/**
* OrganizationRepository
*/
private final OrganizationRepository organizationRepository;
/**
*
* @param redissonClient {@link RedissonClient}
* @param settingRepository {@link SettingRepository}
* @param organizationRepository {@link OrganizationRepository}
*/
public SystemInitializer(RedissonClient redissonClient, SettingRepository settingRepository,
OrganizationRepository organizationRepository) {
this.redissonClient = redissonClient;
this.settingRepository = settingRepository;
this.organizationRepository = organizationRepository;
}
}