package com.gkhy.testFourierSpecialGasMonitor.config.license;
|
|
import cn.hutool.crypto.asymmetric.KeyType;
|
import cn.hutool.crypto.asymmetric.RSA;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
import com.gkhy.testFourierSpecialGasMonitor.commons.domain.Result;
|
import com.gkhy.testFourierSpecialGasMonitor.commons.enums.ResultCode;
|
import com.gkhy.testFourierSpecialGasMonitor.commons.enums.SystemCacheKeyEnum;
|
import com.gkhy.testFourierSpecialGasMonitor.commons.enums.SystemConfigKeyEnum;
|
import com.gkhy.testFourierSpecialGasMonitor.domain.sysAdmin.entity.SysConfig;
|
import com.gkhy.testFourierSpecialGasMonitor.domain.sysAdmin.repository.jpa.SysConfigRepository;
|
import org.redisson.api.RedissonClient;
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import javax.crypto.BadPaddingException;
|
import javax.crypto.Cipher;
|
import javax.crypto.IllegalBlockSizeException;
|
import javax.crypto.NoSuchPaddingException;
|
import javax.crypto.spec.IvParameterSpec;
|
import javax.crypto.spec.SecretKeySpec;
|
import java.nio.charset.StandardCharsets;
|
import java.security.*;
|
import java.security.spec.InvalidKeySpecException;
|
import java.security.spec.X509EncodedKeySpec;
|
import java.util.Base64;
|
import java.util.Optional;
|
|
public class CompanyLicenseDataCache {
|
|
@Autowired
|
private SysConfigRepository sysConfigRepository;
|
|
@Autowired
|
private RedissonClient redissonClient;
|
|
//授权信息
|
private LicenseInfo licenseInfo;
|
|
//部署模式
|
private String deployMode;
|
|
public CompanyLicenseDataCache(String deployMode) {
|
this.deployMode = deployMode;
|
initLicenseInfo(this.deployMode);
|
}
|
|
private void initLicenseInfo(String deployMode){
|
//初始化授权信息,系统启动时执行
|
|
}
|
|
/**
|
* 获取授权证书信息
|
* @return
|
*/
|
public LicenseInfo getLicenseInfo(){
|
if(deployMode != null && deployMode.equals("standalone")){
|
//单机模式
|
return getLocalLicenseInfo();
|
}else if(deployMode != null && deployMode.equals("cluster")){
|
//集群模式
|
return getClusterLicenseInfo();
|
}else {
|
//配置错误
|
return null;
|
}
|
}
|
|
/**
|
* 单机部署,获取本地授权信息
|
* @return
|
*/
|
private LicenseInfo getLocalLicenseInfo() {
|
//已经存在授权信息,直接返回
|
if(licenseInfo != null){
|
return licenseInfo;
|
}
|
//本地不存在授权信息,从数据库读取证书数据
|
Optional<SysConfig> sysConfigOptional = sysConfigRepository.findById(SystemConfigKeyEnum.LICENSE_TXT.getKey());
|
if(!sysConfigOptional.isPresent() || sysConfigOptional.get().getSysValue().isEmpty()){
|
//数据库没有证书信息,返回无效授权
|
licenseInfo = genEmptyLicense();
|
} else{
|
//解码证书文本,获取授权信息
|
String licenseTxt = sysConfigOptional.get().getSysValue();
|
LicenseInfo lic = decodeLicenseData(licenseTxt);
|
if(lic != null){
|
licenseInfo = lic;
|
}else {
|
licenseInfo = genEmptyLicense();
|
}
|
}
|
return licenseInfo;
|
}
|
|
/**
|
* 集群部署,获取redis授权信息
|
* @return
|
*/
|
private LicenseInfo getClusterLicenseInfo() {
|
//已经存在授权信息,直接返回
|
if(licenseInfo != null){
|
return licenseInfo;
|
}
|
//本地不存在授权信息,从数据库读取证书数据
|
Optional<SysConfig> sysConfigOptional = sysConfigRepository.findById(SystemConfigKeyEnum.LICENSE_TXT.getKey());
|
if(!sysConfigOptional.isPresent() || sysConfigOptional.get().getSysValue().isEmpty()){
|
//数据库没有证书信息,返回无效授权
|
licenseInfo = genEmptyLicense();
|
} else{
|
//解码证书文本,获取授权信息
|
String licenseTxt = sysConfigOptional.get().getSysValue();
|
LicenseInfo lic = decodeLicenseData(licenseTxt);
|
if(lic != null){
|
licenseInfo = lic;
|
//将授权信息同步到redis
|
if(updateRedisLicenseInfo(lic).isSuccess()){
|
|
}else {
|
//todo:更新redis缓存失败
|
}
|
}else {
|
licenseInfo = genEmptyLicense();
|
}
|
}
|
return licenseInfo;
|
}
|
|
/**
|
* 更新授权信息
|
* @param licenseTxt
|
* @return
|
*/
|
public Result updateLicense(String licenseTxt){
|
Result result = new Result<>();
|
if(licenseTxt == null || licenseTxt.isEmpty()){
|
result.setCode(ResultCode.PARAM_ERROR_NULL.getCode());
|
result.setMsg("license为空");
|
return result;
|
}
|
LicenseInfo licInfo = decodeLicenseData(licenseTxt);
|
if(licInfo == null){
|
result.setCode(ResultCode.BUSINESS_ERROR.getCode());
|
result.setMsg("license错误");
|
return result;
|
}
|
//1、先更新redis缓存
|
if(updateRedisLicenseInfo(licInfo).isSuccess()){
|
//2、再更新本地缓存
|
licenseInfo = licInfo;
|
result.execSuccess();
|
}else {
|
result.setCode(ResultCode.SYSTEM_ERROR.getCode());
|
result.setMsg("更新redis缓存的license出错");
|
}
|
return result;
|
}
|
|
/**
|
* 更新redis缓存的license
|
* @param licenseInfo
|
* @return
|
*/
|
private Result updateRedisLicenseInfo(LicenseInfo licenseInfo){
|
Result result = new Result<>();
|
if(redissonClient == null)
|
throw new RuntimeException("redis客户端异常");
|
ObjectMapper om = new ObjectMapper();
|
try {
|
String licenseJson = om.writeValueAsString(licenseInfo);
|
redissonClient.getMap(SystemCacheKeyEnum.KEY_SYSTEM_PROP.getKey()).put(SystemCacheKeyEnum.KEY_SYSTEM_LICENSE_INFO.getKey(),licenseJson);
|
result.setCode(ResultCode.OK.getCode());
|
} catch (JsonProcessingException e) {
|
result.setCode(ResultCode.SYSTEM_ERROR.getCode());
|
result.setMsg("license序列化为JSON出错");
|
e.printStackTrace();
|
}
|
return result;
|
}
|
|
/**
|
* 创建无效授权信息
|
* @return
|
*/
|
private LicenseInfo genEmptyLicense(){
|
LicenseInfo empty = new LicenseInfo();
|
empty.setLicenseType(LicenseTypeEnum.INVALID.getType());
|
empty.setCompanyName(null);
|
empty.setBeginTime(null);
|
empty.setEndTime(null);
|
return empty;
|
}
|
|
private LicenseInfo decodeLicenseDataRsa(String licenseTxt){
|
LicenseInfo licenseInfo = null;
|
if(licenseTxt == null || licenseTxt.isEmpty())
|
return null;
|
String aesTxt = null;
|
byte[] aesTxtBytes = Base64.getDecoder().decode(licenseTxt.getBytes(StandardCharsets.UTF_8));
|
try {
|
aesTxt = String.valueOf(Base64.getDecoder().decode(licenseTxt.getBytes(StandardCharsets.UTF_8)));
|
} catch (Exception e) {
|
e.printStackTrace();
|
return null;
|
}
|
if(aesTxt == null || aesTxt.isEmpty())
|
return null;
|
if(aesTxtBytes == null || aesTxtBytes.length == 0)
|
return null;
|
//解析本地KEY
|
|
//todo
|
return null;
|
|
}
|
|
/**
|
* 解码license数据
|
* @param licenseTxt
|
* @return
|
*/
|
private LicenseInfo decodeLicenseData(String licenseTxt){
|
LicenseInfo licenseInfo = null;
|
if(licenseTxt == null || licenseTxt.isEmpty())
|
return null;
|
String aesTxt = null;
|
byte[] aesTxtBytes = Base64.getDecoder().decode(licenseTxt.getBytes(StandardCharsets.UTF_8));
|
try {
|
aesTxt = String.valueOf(Base64.getDecoder().decode(licenseTxt.getBytes(StandardCharsets.UTF_8)));
|
} catch (Exception e) {
|
e.printStackTrace();
|
return null;
|
}
|
if(aesTxt == null || aesTxt.isEmpty())
|
return null;
|
if(aesTxtBytes == null || aesTxtBytes.length == 0)
|
return null;
|
//解析本地KEY
|
LicenseKCon sysKey = getSysKey();
|
if(sysKey == null)
|
return null;
|
//获取用户私有key
|
// LicenseKCon userPrivateKey = getUserPrivateKey(sysKey);
|
LicenseKCon userPrivateKey = getUserPrivateKeyRSA();
|
if(userPrivateKey == null)
|
return null;
|
//使用私有key解密license
|
try {
|
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
cipher.init(Cipher.DECRYPT_MODE,new SecretKeySpec(userPrivateKey.getKey().getBytes(),"AES"),
|
new IvParameterSpec(userPrivateKey.getIv().getBytes()));
|
byte[] rsBytes = cipher.doFinal(aesTxtBytes);
|
String jsonStr = new String(rsBytes,StandardCharsets.UTF_8);
|
// System.out.println("解密后明文:\n"+jsonStr);
|
ObjectMapper om = new ObjectMapper();
|
om.registerModule(new JavaTimeModule());
|
licenseInfo = om.readValue(jsonStr,LicenseInfo.class);
|
} catch (NoSuchAlgorithmException e) {
|
e.printStackTrace();
|
} catch (NoSuchPaddingException e) {
|
e.printStackTrace();
|
} catch (InvalidKeyException e) {
|
e.printStackTrace();
|
} catch (InvalidAlgorithmParameterException e) {
|
e.printStackTrace();
|
} catch (IllegalBlockSizeException e) {
|
e.printStackTrace();
|
} catch (BadPaddingException e) {
|
e.printStackTrace();
|
} catch (JsonProcessingException e) {
|
e.printStackTrace();
|
}
|
return licenseInfo;
|
}
|
|
/**
|
* 获取系统KEY
|
* @return
|
*/
|
private LicenseKCon getSysKey(){
|
//解析本地KEY
|
String key = null;
|
String iv = null;
|
|
String sysKeyStr = new String(Base64.getDecoder().decode(LicenseDataCon.getCon().getPi().getBytes(StandardCharsets.UTF_8)),
|
StandardCharsets.UTF_8);
|
String[] kiArray =sysKeyStr.split("#");
|
if(kiArray == null || kiArray.length !=2){
|
return null;
|
}
|
key = kiArray[0];
|
iv = kiArray[1];
|
|
if(key == null || iv == null || key.isEmpty() || iv.isEmpty())
|
return null;
|
LicenseKCon licenseKCon = new LicenseKCon();
|
licenseKCon.setKey(key);
|
licenseKCon.setIv(iv);
|
return licenseKCon;
|
}
|
|
/**
|
* 用本地key解码获取用户私有key
|
* @param sysKey
|
* @return
|
*/
|
private LicenseKCon getUserPrivateKey(LicenseKCon sysKey){
|
Optional<SysConfig> sysConfigOptional = sysConfigRepository.findById(SystemConfigKeyEnum.LICENSE_U_KEY.getKey());
|
if(sysConfigOptional == null || !sysConfigOptional.isPresent()){
|
return null;
|
}
|
SysConfig sysConfig = sysConfigOptional.get();
|
if(sysConfig.getSysValue() == null || sysConfig.getSysValue().isEmpty())
|
return null;
|
//加密:明文->转base64->aes->转base64
|
//解密:密文->反base64->aes->反base64
|
//明文规则: key#iv
|
String key = null;
|
String iv = null;
|
|
|
byte[] rsBytes = new byte[0];
|
try {
|
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
cipher.init(Cipher.DECRYPT_MODE,new SecretKeySpec(sysKey.getKey().getBytes(),"AES"),
|
new IvParameterSpec(sysKey.getIv().getBytes()));
|
rsBytes = cipher.doFinal(Base64.getDecoder().decode(sysConfig.getSysValue().getBytes(StandardCharsets.UTF_8)));
|
} catch (NoSuchAlgorithmException e) {
|
e.printStackTrace();
|
} catch (NoSuchPaddingException e) {
|
e.printStackTrace();
|
} catch (InvalidKeyException e) {
|
e.printStackTrace();
|
} catch (InvalidAlgorithmParameterException e) {
|
e.printStackTrace();
|
} catch (IllegalBlockSizeException e) {
|
e.printStackTrace();
|
} catch (BadPaddingException e) {
|
e.printStackTrace();
|
}
|
|
String[] kiArray = new String(Base64.getDecoder().decode(rsBytes), StandardCharsets.UTF_8).split("#");
|
if(kiArray == null || kiArray.length != 2){
|
return null;
|
}
|
key = kiArray[0];
|
iv = kiArray[1];
|
if(key == null || iv == null || key.isEmpty() || iv.isEmpty())
|
return null;
|
LicenseKCon licenseKCon = new LicenseKCon();
|
licenseKCon.setKey(key);
|
licenseKCon.setIv(iv);
|
return licenseKCon;
|
}
|
|
private LicenseKCon getUserPrivateKeyRSA(){
|
//1、从数据库获取加密KEY
|
Optional<SysConfig> sysConfigOptional = sysConfigRepository.findById(SystemConfigKeyEnum.LICENSE_U_KEY.getKey());
|
if(sysConfigOptional == null || !sysConfigOptional.isPresent()){
|
return null;
|
}
|
SysConfig sysConfig = sysConfigOptional.get();
|
if(sysConfig.getSysValue() == null || sysConfig.getSysValue().isEmpty())
|
return null;
|
//2、解密取得secretKey 和 IV
|
LicenseDataCon dataConf = LicenseDataCon.getCon();
|
byte[] rsBytes = null;
|
|
RSA rsa = new RSA();
|
PublicKey pk =
|
null;
|
try {
|
pk = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(dataConf.getPublicKey())));
|
} catch (InvalidKeySpecException e) {
|
e.printStackTrace();
|
} catch (NoSuchAlgorithmException e) {
|
e.printStackTrace();
|
}
|
rsa.setPublicKey(pk);
|
rsBytes = rsa.decrypt(Base64.getDecoder().decode(sysConfig.getSysValue()), KeyType.PublicKey);
|
|
//解密后处理
|
if(rsBytes == null || rsBytes.length == 0){
|
return null;
|
}
|
//明文规则: key#iv
|
String kiStr = new String(rsBytes, StandardCharsets.UTF_8);
|
String[] kiArray = kiStr.split("#");
|
if(kiArray == null || kiArray.length != 2){
|
return null;
|
}
|
String key = kiArray[0];
|
String iv = kiArray[1];
|
if(key == null || iv == null || key.isEmpty() || iv.isEmpty())
|
return null;
|
LicenseKCon licenseKCon = new LicenseKCon();
|
licenseKCon.setKey(key);
|
licenseKCon.setIv(iv);
|
return licenseKCon;
|
}
|
}
|