REM:
1. 增加接口协议响应加密功能
2. 增加接口响应协议加密方式相关配置
3. controller 层支持协议传输加解密功能
4. 优化通信协议接口定义
This commit is contained in:
HuangXin 2020-08-26 17:56:34 +08:00
parent f7cd5d0d3a
commit 955778b3b9
10 changed files with 239 additions and 52 deletions

View File

@ -186,13 +186,22 @@ public enum ErrorCode {
*/
ERR_ENCRYPT_3DES(105, "3DES加密失败"),
/**
* Err decrypt unknown error code.
* The Err decrypt unknown.
*/
ERR_DECRYPT_UNKNOWN(106, "不支持的解密算法"),
/**
* Err encrypt unknown error code.
* The Err encrypt unknown.
*/
ERR_ENCRYPT_UNKNOWN(107, "不支持的加密算法"),
/**
* Err json encode error code.
*/
ERR_JSON_ENCODE(108, "Json 序列号错误"),
/**
* Err json decode error code.
*/
ERR_JSON_DECODE(109, "Json 反序列化错误"),
;
/**

View File

@ -11,6 +11,7 @@ import com.dispose.pojo.dto.protocol.base.ValidGroups;
import com.dispose.pojo.po.MulReturnType;
import com.dispose.service.UserAccountService;
import com.security.annotation.Decryption;
import com.security.annotation.Encryption;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
@ -38,6 +39,8 @@ import java.security.NoSuchAlgorithmException;
@Api(value = "处置平台认证接口", tags = "处置平台认证接口")
@Component
@Validated
@Encryption
@Decryption
public class AuthController {
/**
* The User account service.
@ -55,7 +58,7 @@ public class AuthController {
@PostMapping("/login")
@ResponseBody
@ApiOperation("登录")
public ProtocolRespDTO<? extends BaseRespStatus> userLogin(@Decryption
public ProtocolRespDTO<? extends BaseRespStatus> userLogin(
@Validated(ValidGroups.LoginReqValid.class)
@RequestBody ProtocolReqDTO<LoginReq> mr)
throws NoSuchAlgorithmException {
@ -95,6 +98,7 @@ public class AuthController {
@PostMapping("/logout")
@ResponseBody
@ApiOperation("注销")
@Encryption
public ProtocolRespDTO<? extends BaseRespStatus> userLogout(@Validated(ValidGroups.LogoutReqValid.class)
@RequestBody ProtocolReqDTO<LoginReq> mr,
@RequestHeader HttpHeaders headers) { // 注销用户登录

View File

@ -27,6 +27,8 @@ import com.dispose.pojo.entity.DisposeDevice;
import com.dispose.pojo.po.MulReturnType;
import com.dispose.service.DisposeDeviceManagerService;
import com.github.pagehelper.PageInfo;
import com.security.annotation.Decryption;
import com.security.annotation.Encryption;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
@ -55,6 +57,8 @@ import java.util.List;
@Api(value = "处置平台设备管理接口", tags = "处置平台设备管理接口")
@Component
@Validated
@Encryption
@Decryption
public class DisposeDeviceManagerController {
/**

View File

@ -19,7 +19,7 @@ import java.lang.reflect.Type;
*/
@Slf4j
@RestControllerAdvice
public class ProtocolSecurity implements RequestBodyAdvice {
public class RequestProtocolSecurity implements RequestBodyAdvice {
/**
* Supports boolean.
*
@ -32,7 +32,8 @@ public class ProtocolSecurity implements RequestBodyAdvice {
public boolean supports(@NotNull MethodParameter methodParameter,
@NotNull Type type,
@NotNull Class<? extends HttpMessageConverter<?>> aClass) {
return methodParameter.hasParameterAnnotation(Decryption.class);
return methodParameter.getContainingClass().isAnnotationPresent(Decryption.class)
|| methodParameter.hasMethodAnnotation(Decryption.class);
}
/**

View File

@ -0,0 +1,65 @@
package com.dispose.interceptor;
import com.dispose.common.ProtoCryptoType;
import com.dispose.common.SecurityConfigValue;
import com.security.annotation.Encryption;
import com.security.protocol.EncryptResponseProtocol;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* The type Response protocol security.
*
* @author <huangxin@cmhi.chinamoblie.com>
*/
@Slf4j
@RestControllerAdvice
public class ResponseProtocolSecurity implements ResponseBodyAdvice<Object> {
/**
* Supports boolean.
*
* @param methodParameter the method parameter
* @param aClass the a class
* @return the boolean
*/
@Override
public boolean supports(@NotNull MethodParameter methodParameter,
@NotNull Class<? extends HttpMessageConverter<?>> aClass) {
return methodParameter.getContainingClass().isAnnotationPresent(Encryption.class)
|| methodParameter.hasMethodAnnotation(Encryption.class);
}
/**
* Before body write protocol resp dto.
*
* @param o the o
* @param methodParameter the method parameter
* @param mediaType the media type
* @param aClass the a class
* @param serverHttpRequest the server http request
* @param serverHttpResponse the server http response
* @return the protocol resp dto
*/
@Override
@NotNull
public Object beforeBodyWrite(Object o,
@NotNull MethodParameter methodParameter,
@NotNull MediaType mediaType,
@NotNull Class<? extends HttpMessageConverter<?>> aClass,
@NotNull ServerHttpRequest serverHttpRequest,
@NotNull ServerHttpResponse serverHttpResponse) {
if (SecurityConfigValue.SECURITY_PROTOCOL_TYPE == ProtoCryptoType.CRYPTO_NONE.getCode()) {
return o;
} else {
return new EncryptResponseProtocol(o, SecurityConfigValue.SECURITY_PROTOCOL_TYPE).toEncryptObject();
}
}
}

View File

@ -2,7 +2,7 @@ package com.dispose.pojo.dto.protocol.base;
import com.dispose.common.ConstValue;
import com.dispose.common.ErrorCode;
import com.dispose.common.ProtoCryptoType;
import com.dispose.common.SecurityConfigValue;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.annotations.ApiModelProperty;
@ -10,6 +10,7 @@ import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* The type Protocol resp dto.
@ -17,6 +18,7 @@ import lombok.NoArgsConstructor;
* @param <T> the type parameter
* @author <huangxin@cmhi.chinamoblie.com>
*/
@Slf4j
@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
@ -29,7 +31,7 @@ public class ProtocolRespDTO<T> extends BaseProtocolDTO<T> {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
/**
* 状态码用于记录服务器返回状态信息例如HTTP返回值等.
* The Code.
*/
@ApiModelProperty(value = "服务器返回状态码", example = "200")
private Integer code;
@ -39,11 +41,19 @@ public class ProtocolRespDTO<T> extends BaseProtocolDTO<T> {
*
* @param <T> the type parameter
* @param err the err
* @param obj the obj
* @param httpCode the http code
* @param respMsg the resp msg
* @return the protocol resp dto
*/
public static <T> ProtocolRespDTO<T> result(ErrorCode err, T obj) {
return result(err, obj, ProtoCryptoType.CRYPTO_NONE.getCode());
private static <T> ProtocolRespDTO<T> result(ErrorCode err, Integer httpCode, T respMsg) {
ProtocolRespDTO<T> resp = new ProtocolRespDTO<>();
resp.setVer(ConstValue.Protocol.VERSION);
resp.setCode(httpCode);
resp.setCryptoType(SecurityConfigValue.SECURITY_PROTOCOL_TYPE);
resp.setTimeStamp(System.currentTimeMillis());
resp.setMsgContent(respMsg);
return resp;
}
/**
@ -52,19 +62,10 @@ public class ProtocolRespDTO<T> extends BaseProtocolDTO<T> {
* @param <T> the type parameter
* @param err the err
* @param respMsg the resp msg
* @param crypto the crypto
* @return the protocol resp dto
*/
public static <T> ProtocolRespDTO<T> result(ErrorCode err, T respMsg, Integer crypto) {
ProtocolRespDTO<T> resp = new ProtocolRespDTO<>();
resp.setVer(ConstValue.Protocol.VERSION);
resp.setCode(err.getHttpCode());
resp.setCryptoType(crypto);
resp.setTimeStamp(System.currentTimeMillis());
resp.setMsgContent(respMsg);
return resp;
public static <T> ProtocolRespDTO<T> result(ErrorCode err, T respMsg) {
return result(err, err.getHttpCode(), respMsg);
}
/**
@ -74,19 +75,8 @@ public class ProtocolRespDTO<T> extends BaseProtocolDTO<T> {
* @return the protocol resp dto
*/
public static ProtocolRespDTO<BaseRespStatus> result(ErrorCode err) {
ProtocolRespDTO<BaseRespStatus> resp = new ProtocolRespDTO<>();
BaseRespStatus rspMsg = new BaseRespStatus();
rspMsg.setStatus(err.getCode());
rspMsg.setMessage(new String[] {err.getMsg()});
resp.setVer(ConstValue.Protocol.VERSION);
resp.setCode(err.getHttpCode());
resp.setCryptoType(ProtoCryptoType.CRYPTO_NONE.getCode());
resp.setTimeStamp(System.currentTimeMillis());
resp.setMsgContent(rspMsg);
return resp;
BaseRespStatus rspMsg = new BaseRespStatus(err.getCode(), new String[]{err.getMsg()});
return result(err, err.getHttpCode(), rspMsg);
}
/**
@ -98,17 +88,7 @@ public class ProtocolRespDTO<T> extends BaseProtocolDTO<T> {
* @return the protocol resp dto
*/
public static ProtocolRespDTO<BaseRespStatus> result(ErrorCode errCode, Integer httpCode, String[] message) {
ProtocolRespDTO<BaseRespStatus> resp = new ProtocolRespDTO<>();
BaseRespStatus rspMsg = new BaseRespStatus();
rspMsg.setStatus(errCode.getCode());
rspMsg.setMessage(message);
resp.setVer(ConstValue.Protocol.VERSION);
resp.setCode(httpCode);
resp.setCryptoType(ProtoCryptoType.CRYPTO_NONE.getCode());
resp.setTimeStamp(System.currentTimeMillis());
resp.setMsgContent(rspMsg);
return resp;
BaseRespStatus rspMsg = new BaseRespStatus(errCode.getCode(), message);
return result(errCode, httpCode, rspMsg);
}
}

View File

@ -10,7 +10,7 @@ import java.lang.annotation.Target;
*
* @author <huangxin@cmhi.chinamoblie.com>
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Decryption {
}

View File

@ -10,7 +10,7 @@ import java.lang.annotation.Target;
*
* @author <huangxin@cmhi.chinamoblie.com>
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Encryption {
}

View File

@ -73,7 +73,7 @@ public class CryptoHelper {
/**
* Aes 256 encryption byte [ ].
*
* @param plaintext the ciphertext
* @param plaintext the plaintext
* @param aesKey the aes key
* @return the byte [ ]
* @throws NoSuchAlgorithmException the no such algorithm exception
@ -145,4 +145,29 @@ public class CryptoHelper {
cipher.init(Cipher.ENCRYPT_MODE, secretKey, sr);
return cipher.doFinal(ciphertext);
}
/**
* Des encryption byte [ ].
*
* @param plaintext the plaintext
* @param desKey the des key
* @return the byte [ ]
* @throws InvalidKeyException the invalid key exception
* @throws NoSuchAlgorithmException the no such algorithm exception
* @throws InvalidKeySpecException the invalid key spec exception
* @throws NoSuchPaddingException the no such padding exception
* @throws BadPaddingException the bad padding exception
* @throws IllegalBlockSizeException the illegal block size exception
*/
public static byte[] desEncryption(byte[] plaintext, String desKey) throws InvalidKeyException,
NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, BadPaddingException,
IllegalBlockSizeException {
SecureRandom sr = new SecureRandom();
DESKeySpec desKeySpec = new DESKeySpec(desKey.getBytes());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
Cipher cipher = Cipher.getInstance(DES_ALGORITHM_STR);
cipher.init(Cipher.DECRYPT_MODE, secretKey, sr);
return cipher.doFinal(plaintext);
}
}

View File

@ -0,0 +1,99 @@
package com.security.protocol;
import com.dispose.common.ConstValue;
import com.dispose.common.ErrorCode;
import com.dispose.common.ProtoCryptoType;
import com.dispose.common.SecurityConfigValue;
import com.dispose.pojo.dto.protocol.base.ProtocolRespDTO;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.security.arithmetic.CryptoHelper;
import com.security.exception.SecurityProtocolException;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
/**
* The type Encrypt response protocol.
*
* @author <huangxin@cmhi.chinamoblie.com>
*/
@Slf4j
public class EncryptResponseProtocol {
/**
* The Object mapper.
*/
private final ObjectMapper objectMapper = new ObjectMapper();
/**
* The Object.
*/
private final Object object;
/**
* The Encrypt type.
*/
private final Integer encryptType;
/**
* Instantiates a new Encrypt response protocol.
*
* @param object the object
* @param encType the enc type
*/
public EncryptResponseProtocol(Object object, Integer encType) {
this.encryptType = encType;
this.object = object;
}
/**
* To encrypt object protocol resp dto.
*
* @return the protocol resp dto
*/
public ProtocolRespDTO<String> toEncryptObject() {
ProtocolRespDTO<String> cryptoObject = new ProtocolRespDTO<>();
cryptoObject.setVer(ConstValue.Protocol.VERSION);
cryptoObject.setCryptoType(SecurityConfigValue.SECURITY_PROTOCOL_TYPE);
cryptoObject.setTimeStamp(System.currentTimeMillis());
String msgContentJsonString;
try {
Method getMsgMethod = object.getClass().getMethod("getMsgContent");
Method getCode = object.getClass().getMethod("getCode");
msgContentJsonString = new ObjectMapper().writeValueAsString(getMsgMethod.invoke(object));
cryptoObject.setCode((Integer) getCode.invoke(object));
} catch (Exception e) {
log.error("Json encode message error: {}", object);
throw new SecurityProtocolException(ErrorCode.ERR_SYSTEMEXCEPTION);
}
if (encryptType == ProtoCryptoType.CRYPTO_BASE64.getCode()) {
cryptoObject.setMsgContent(CryptoHelper.base64Encryption(msgContentJsonString.getBytes(StandardCharsets.UTF_8)));
} else if (encryptType == ProtoCryptoType.CRYPTO_AES256.getCode()) {
try {
byte[] encode = CryptoHelper.aes256Encryption(msgContentJsonString.getBytes(StandardCharsets.UTF_8),
SecurityConfigValue.AES_KEY);
cryptoObject.setMsgContent(CryptoHelper.base64Encryption(encode));
} catch (Exception e) {
log.error("AES256 encode message error: {}", msgContentJsonString);
throw new SecurityProtocolException(ErrorCode.ERR_DECRYPT_AES256);
}
} else if (encryptType == ProtoCryptoType.CRYPTO_DES.getCode()) {
try {
byte[] encode = CryptoHelper.desEncryption(msgContentJsonString.getBytes(StandardCharsets.UTF_8),
SecurityConfigValue.DES_KEY);
cryptoObject.setMsgContent(CryptoHelper.base64Encryption(encode));
} catch (Exception e) {
log.error("DES256 encode message error: {}", msgContentJsonString);
throw new SecurityProtocolException(ErrorCode.ERR_DECRYPT_3DES);
}
} else {
log.error("Unknown protocol security type: {}, {}", encryptType, msgContentJsonString);
throw new SecurityProtocolException(ErrorCode.ERR_ENCRYPT_UNKNOWN);
}
return cryptoObject;
}
}