@@ -1,9 +1,21 @@
package com.njcn.gather.system.reg.service.impl ;
import cn.hutool.core.bean.BeanUtil ;
import cn.hutool.core.net.NetUtil ;
import cn.hutool.core.util.ObjectUtil ;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl ;
import com.fasterxml.jackson.databind.ObjectMapper ;
import com.njcn.common.pojo.enums.common.DataStateEnum ;
import com.njcn.common.pojo.exception.BusinessException ;
import com.njcn.common.utils.EncryptionUtil ;
import com.njcn.common.utils.sm.Sm4Utils ;
import com.njcn.gather.system.dictionary.pojo.enums.DictDataEnum ;
import com.njcn.gather.system.dictionary.pojo.po.DictData ;
import com.njcn.gather.system.dictionary.service.IDictDataService ;
import com.njcn.gather.system.dictionary.service.IDictTypeService ;
import com.njcn.gather.system.reg.mapper.SysRegResMapper ;
import com.njcn.gather.system.reg.pojo.dto.RegInfoData ;
import com.njcn.gather.system.reg.pojo.enums.RegResponseEnum ;
import com.njcn.gather.system.reg.pojo.param.SysRegResParam ;
import com.njcn.gather.system.reg.pojo.po.SysRegRes ;
import com.njcn.gather.system.reg.pojo.vo.SysRegResVO ;
@@ -13,8 +25,18 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service ;
import org.springframework.transaction.annotation.Transactional ;
import java.util.HashMap ;
import java.util.Map ;
import javax.crypto.Cipher ;
import java.net.InetAddress ;
import java.net.UnknownHostException ;
import java.nio.charset.StandardCharsets ;
import java.security.Key ;
import java.security.KeyFactory ;
import java.security.PrivateKey ;
import java.security.PublicKey ;
import java.security.spec.PKCS8EncodedKeySpec ;
import java.security.spec.X509EncodedKeySpec ;
import java.time.LocalDate ;
import java.util.* ;
/**
* @author caozehui
@@ -24,6 +46,39 @@ import java.util.Map;
@Service
@RequiredArgsConstructor
public class SysRegResServiceImpl extends ServiceImpl < SysRegResMapper , SysRegRes > implements ISysRegResService {
/**
* 固定私钥
*/
private static final String fixedPrivateKeyStr = " -----BEGIN PRIVATE KEY----- \ n " +
" MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDTC6MQkjHAIyPQ \ n " +
" 12tfSBsmS12OspsmJORW2cf7s+xwe3lJ3nb9KohjAuRBG4jLceAXdZoCuk1+Xt8l \ n " +
" kesXp930DWmb7SBHLa7imGgvIm/9hP7Y48yDJqM2Ia6CFbMCmLYCiU3oDLZ2DuUq \ n " +
" QbE2j9QuTTMiOVHBy4M82XwkEXNfIQez9PB+Osex2X9FesyMoWvsoOcnDD8iWmbP \ n " +
" Ag0syuutt4YkrU8IWC5v2vyTxb+N+F36wqbC8td1wOgUrf2K3kQtTe7xB1b3i5RI \ n " +
" DAsjxPd1a3uzJVjJ7Onla+B4dkFGOSlX/w8/GJQzMgegskKEPRONyXRWCaVpBt9O \ n " +
" 6yDjKz7vAgMBAAECggEATnj+vowlnJRUXnSjM5AbrD8MwCEQSHwiPVsIHcLWkTKQ \ n " +
" NFPYeaVFhk9OcRkcYc1rbj2nsQj2BJ2hKpaZzDd6c6NDGBvxSxYk95OE9bW/34wC \ n " +
" uMHnSwLkYB3hBfSslbQTxVipk7WaaMZ8FpzLmIaddkP1Ve3rRPx3xXn2y3CDriRs \ n " +
" WxVKm4+ri8Ncnk0dBqjEBNwgdsvRlxPMAB9t4mTxS6NENriIWgiBGDiMFT3dstkw \ n " +
" tIvxX/gdrLCd9CbV1iZgH+a/CiKIYcSGzPiYfwEi446cPZwfwYo65C1HBS1mMJju \ n " +
" FwLw0r9OQ9LEsO+ar6d7hss4RmHgRR1JdQyBoq/wbQKBgQD1kkE1TfJpFmCpWR/P \ n " +
" wdl88ABnwEZtaKKMS1A+T2+ywEl3y+iUPoouJ+69zG0s7NuwpeJ2c1S0BB+yFRWx \ n " +
" ExGjJ2Z0GbK++f2R38Y3kvj2lGiB4AZ1sentTuatGHWRzwEd913swrKd/fkFBA/I \ n " +
" x38Mmq7wDqkqIxNh20W2jWWd3QKBgQDcAgg39l5zYeNIUdm/PQINd4G1UjCTcgvn \ n " +
" +7AFpuoCYfx9ReXzvLjGDs8VmuoBIg5Y4bWIUhTSQVQIIRE12EXrysawHs7loegp \ n " +
" FTU6cZAjxT72sRhesr12f5s5Hd3zaMB0Y8PUljAG7lvAVNPQDUkAL7+bmYLxWokq \ n " +
" G/FHJooBOwKBgQCidDWVKNKTuI0Lmv0TeL8DCtaJzEYK/OyDeRNFlVFkZBZ2HLvo \ n " +
" zhKlhB9JCiKzVKHlE2hkSdmgGRZKve4SrXW+hEMfzRxVgJXB2dKMUztGDFmyiVxc \ n " +
" oe0J42dw3Txx0AqCI3HMPeTh5fDF47D5dxhSY0YVYu2ABaI920wb/yBZNQKBgGlz \ n " +
" P+Uy3QqIvJuJP8j9wOIbibwS7N1/KF3EsRXEbx09Qfv5aMJujlG//1nnqolofV/0 \ n " +
" r0HrtbchQNm0n78jLkBaLOl1ms1N0Sz/0Ud17xR2EjvDnl6lZVJKz2eM/TkR2Ezx \ n " +
" FIfshJCN5sRE5FEwTPEd8cTuy2hLcLsSMY9c1YDJAoGBAMIPLraI8c7h4hOCNE66 \ n " +
" Eg2nEOcqCzmIYTS6ARCPYrOC4cx23+uAScbZCq+vBk34KSJyun1OgfvnRmVerpUU \ n " +
" lld8v62FR3FnNwSY/zeySP8ENCzAUluql0yHzgpBwF3NNYihVdYY4Lm3vlUe4fTt \ n " +
" krNC84FOePuC5qaIefZ03oRX \ n " +
" -----END PRIVATE KEY----- " ;
private final IDictDataService dictDataService ;
@Override
public SysRegRes getRegResByType ( String type ) {
@@ -33,11 +88,56 @@ public class SysRegResServiceImpl extends ServiceImpl<SysRegResMapper, SysRegRes
@Override
@Transactional ( rollbackFor = { Exception . class } )
public boolean addRegRes ( SysRegResParam sysRegResParam ) {
SysRegRes sysR egRes = new SysRegRes ( ) ;
BeanUtil . copyProperties ( sysRegResParam , sysRegRes ) ;
sysRegRes . setState ( DataStateEnum . ENABLE . getCode ( ) ) ;
// todo 解析注册码
return this . save ( sysRegRes ) ;
List < SysRegRes> r egResList = new ArrayList < > ( ) ;
RegInfoData regInfoData = decodeRegistrationCode ( sysRegResParam . getCode ( ) ) ;
if ( ObjectUtil . isNotNull ( regInfoData ) ) {
// 对比Mac地址
String mac = getMAC ( ) ;
if ( ! mac . equals ( regInfoData . getMacAddress ( ) ) ) {
throw new BusinessException ( RegResponseEnum . MAC_ADDRESS_NOT_MATCH ) ;
}
// 比对到期日期
String maxExpireDate = regInfoData . getExpireDateList ( ) . stream ( ) . max ( ( a , b ) - > a . compareTo ( b ) ) . get ( ) ;
if ( LocalDate . parse ( maxExpireDate ) . isBefore ( LocalDate . now ( ) ) ) {
throw new BusinessException ( RegResponseEnum . REGISTRATION_CODE_EXPIRED ) ;
}
for ( int i = 0 ; i < regInfoData . getTypeList ( ) . size ( ) ; i + + ) {
// 忽略过期的
if ( LocalDate . parse ( regInfoData . getExpireDateList ( ) . get ( i ) ) . isBefore ( LocalDate . now ( ) ) ) {
continue ;
}
SysRegRes sysRegRes = new SysRegRes ( ) ;
BeanUtil . copyProperties ( sysRegResParam , sysRegRes ) ;
sysRegRes . setState ( DataStateEnum . ENABLE . getCode ( ) ) ;
sysRegRes . setCode ( sysRegResParam . getCode ( ) ) ;
sysRegRes . setExpireDate ( EncryptionUtil . encodeString ( 1 , regInfoData . getExpireDateList ( ) . get ( i ) ) ) ;
DictData dictData = dictDataService . getDictDataByCode ( regInfoData . getTypeList ( ) . get ( i ) ) ;
if ( ObjectUtil . isNotNull ( dictData ) ) {
sysRegRes . setType ( dictData . getId ( ) ) ;
}
sysRegRes . setRealTime ( 20 ) ;
sysRegRes . setStatistics ( 5 ) ;
sysRegRes . setFlicker ( 1 ) ;
if ( regInfoData . getTypeList ( ) . get ( i ) . equals ( DictDataEnum . CONTRAST . getCode ( ) ) ) {
sysRegRes . setWaveRecord ( 1 ) ;
sysRegRes . setRealTime ( 200 ) ;
sysRegRes . setStatistics ( 5 ) ;
sysRegRes . setFlicker ( 3 ) ;
}
regResList . add ( sysRegRes ) ;
}
}
// 删除原有的所有数据
this . remove ( null ) ;
return this . saveBatch ( regResList ) ;
}
@Override
@@ -52,13 +152,100 @@ public class SysRegResServiceImpl extends ServiceImpl<SysRegResMapper, SysRegRes
}
@Override
public Map < String , SysRegResVO> listRegRes ( ) {
Map < String , SysRegResVO > map = new HashMap < > ( ) ;
this . list ( ) . forEach ( item - > {
SysRegResVO sysRegResVO = new SysRegResVO ( ) ;
BeanUtil . copyProperties ( item , sysRegResVO ) ;
map . put ( item . getType ( ) , sysRegResVO ) ;
public SysRegResVO listRegRes ( ) {
// todo 需要切面检测是否到期, 到期则状态设为0
SysRegResVO sysRegResVO = new SysRegResVO ( ) ;
List < String > typeList = new ArrayList < > ( ) ;
List < String > expireDateList = new ArrayList < > ( ) ;
List < SysRegRes > regResList = this . lambdaQuery ( ) . eq ( SysRegRes : : getState , DataStateEnum . ENABLE . getCode ( ) ) . list ( ) ;
if ( ObjectUtil . isNotEmpty ( regResList ) ) {
sysRegResVO . setCode ( regResList . get ( 0 ) . getCode ( ) ) ;
}
regResList . forEach ( item - > {
DictData dictData = dictDataService . getDictDataById ( item . getType ( ) ) ;
if ( ObjectUtil . isNotNull ( dictData ) ) {
typeList . add ( dictData . getCode ( ) ) ;
}
expireDateList . add ( EncryptionUtil . decoderString ( 1 , item . getExpireDate ( ) ) ) ;
} ) ;
return map ;
sysRegResVO . setTypeList ( typeList ) ;
sysRegResVO . setExpireDateList ( expireDateList ) ;
return sysRegResVO ;
}
/**
* 使用hutool工具获取本机mac地址
*
* @return mac地址
*/
private static String getMAC ( ) {
InetAddress inetAddress = null ;
try {
inetAddress = InetAddress . getLocalHost ( ) ;
} catch ( UnknownHostException e ) {
throw new BusinessException ( RegResponseEnum . GET_MAC_ADDRESS_FAILED ) ;
}
return NetUtil . getMacAddress ( inetAddress ) ;
}
/**
* 解析 PEM 格式的密钥
*
* @param pem PEM 格式的密钥
* @return 密钥对象
* @throws Exception
*/
private static Key parsePemKey ( String pem ) throws Exception {
// 去掉 PEM 格式中的头部和尾部
String cleanPem = pem
. replaceAll ( " -----BEGIN (.*?)----- " , " " )
. replaceAll ( " -----END (.*?)----- " , " " )
. replaceAll ( " \\ s+ " , " " ) ; // 移除换行和空格
byte [ ] decodedKey = Base64 . getDecoder ( ) . decode ( cleanPem ) ;
// 根据密钥类型导入密钥
if ( pem . contains ( " PRIVATE " ) ) {
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec ( decodedKey ) ;
KeyFactory keyFactory = KeyFactory . getInstance ( " RSA " ) ;
PrivateKey privateKey = keyFactory . generatePrivate ( keySpec ) ;
return privateKey ;
} else {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec ( decodedKey ) ;
KeyFactory keyFactory = KeyFactory . getInstance ( " RSA " ) ;
PublicKey publicKey = keyFactory . generatePublic ( keySpec ) ;
return publicKey ;
}
}
/**
* 解析注册码
*
* @param encryptedCode 加密后的注册码
* @return
*/
public static RegInfoData decodeRegistrationCode ( String encryptedCode ) {
try {
byte [ ] encryptedData = Base64 . getDecoder ( ) . decode ( encryptedCode ) ;
Key privateKey = parsePemKey ( fixedPrivateKeyStr ) ;
// 使用 RSA/OAEP 解密
Cipher cipher = Cipher . getInstance ( " RSA/ECB/OAEPWithSHA-256AndMGF1Padding " ) ;
cipher . init ( Cipher . DECRYPT_MODE , privateKey ) ;
byte [ ] decryptedData = cipher . doFinal ( encryptedData ) ;
// 将解密后的字节数组转换为字符串
String decodedString = new String ( decryptedData , StandardCharsets . UTF_8 ) ;
ObjectMapper objectMapper = new ObjectMapper ( ) ;
RegInfoData regInfoData = objectMapper . readValue ( decodedString , RegInfoData . class ) ;
if ( ObjectUtil . isNull ( regInfoData ) | | regInfoData . getTypeList ( ) . size ( ) = = 0 | | regInfoData . getTypeList ( ) . size ( ) ! = regInfoData . getExpireDateList ( ) . size ( ) ) {
throw new BusinessException ( RegResponseEnum . REGISTRATION_CODE_FORMAT_ERROR ) ;
}
return regInfoData ;
} catch ( Exception e ) {
throw new BusinessException ( RegResponseEnum . REGISTRATION_CODE_FORMAT_ERROR ) ;
}
}
}