package com.gkhy.labRiskManage.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.labRiskManage.commons.domain.Result; import com.gkhy.labRiskManage.commons.enums.ResultCode; import com.gkhy.labRiskManage.commons.enums.SystemCacheKeyEnum; import com.gkhy.labRiskManage.commons.enums.SystemConfigKeyEnum; import com.gkhy.labRiskManage.domain.sysAdmin.entity.SysConfig; import com.gkhy.labRiskManage.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 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 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 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 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; } }