package cn.video110.iot.open.aspect;
import cn.video110.iot.base.errorcode.SignErrorCode;
import cn.video110.iot.open.utils.SignUtil;
import cn.video110.starter.mvc.common.CommonResponse;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* 参数签名验证
* @author
* @date 2020/07/23
*/
@Slf4j
@Aspect //参数
@Component //组件
public class SignValidateAspect {
private static String APP_KEY = "407af810068111ea95f4852d6a259567";
private static String APP_SECRET = "b645d880068111ea8f09cf8592eb9fbc";
private static String APP_PASSWORD = "6AEB57F8DA93860A19514592A154BEF8";
/**
* header 中验签参数
*/
private final String[] SIGN_HEADER = new String[]{
"x-clss-iot-authorization",
"x-clss-iot-timestamp",
"x-clss-iot-salt",
"x-clss-iot-appkey"
};
private final String headerAuthorization = "x-clss-iot-authorization";
private final String headerTimestamp = "x-clss-iot-timestamp";
private final String headerSalt = "x-clss-iot-salt";
private final String headerAppKey = "x-clss-iot-appkey";
/**
* 签名验证 表示所有的带有SignValidate的注解
*/
@Pointcut("@annotation(cn.video110.iot.open.aspect.SignValidate)")
public void signValidate() {
}
@Around("signValidate()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Object response = null;
ServletRequestAttributes attributes = (ServletRequestAttributes)
RequestContextHolder.getRequestAttributes();
// 获取当前的Request的实体
HttpServletRequest request = attributes.getRequest();
Map<String, String> signHeader = getSignHeader(request);
//校验header
CommonResponse checkResult = checkHeader(signHeader);
if (!checkResult.isStatus()) {
return checkResult;
}
checkResult = verifySignAndDecrypt(request, signHeader, joinPoint);
if (!checkResult.isStatus()) {
return checkResult;
}
response = joinPoint.proceed((Object[]) checkResult.getObj());
return response;
}
/**
* 获取header签名用的字段
*/
private Map<String, String> getSignHeader(HttpServletRequest request) {
Enumeration<String> headerNames = request.getHeaderNames();
Map<String, String> headerMap = new HashMap();
List<String> signList = Arrays.asList(SIGN_HEADER);
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
if (signList.contains(headerName)) {
String headerValue = request.getHeader(headerName);
headerMap.put(headerName, headerValue);
}
}
return headerMap;
}
/**
* 校验header内参数
*
* @param signHeader header签名参数
* @return CommonResponse 校验结果
*/
private CommonResponse checkHeader(Map<String, String> signHeader) {
if (!signHeader.containsKey(headerAuthorization) || StringUtils
.isBlank(signHeader.get(headerAuthorization))) {
return CommonResponse.error(SignErrorCode.NON_AUTHORIZATION);
}
if (!signHeader.containsKey(headerTimestamp) || StringUtils
.isBlank(signHeader.get(headerTimestamp))) {
return CommonResponse.error(SignErrorCode.NON_TIMESTAMP);
}
if (!signHeader.containsKey(headerSalt) || StringUtils
.isBlank(signHeader.get(headerSalt))) {
return CommonResponse.error(SignErrorCode.NON_SALT);
}
if (!signHeader.containsKey(headerAppKey) || StringUtils
.isBlank(signHeader.get(headerAppKey))) {
return CommonResponse.error(SignErrorCode.NON_APPKEY);
}
return CommonResponse.success();
}
private CommonResponse<Object[]> verifySignAndDecrypt(HttpServletRequest request,
Map<String, String> signHeader,
ProceedingJoinPoint joinPoint) {
//获取参数
Object[] args = joinPoint.getArgs();
CommonResponse response = null;
// 获取连接点的方法签名对象;
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
String[] params = methodSignature.getParameterNames();
if (params.length == 0) {
log.info("当前切入点方法{}没有需要验签的参数。", methodSignature.getName());
return CommonResponse.success(args);
}
// 获得注解中的信息
Method method = methodSignature.getMethod();
SignValidate signValidate = method.getAnnotation(SignValidate.class);
Integer index = ArrayUtils.indexOf(params, signValidate.paramName());
if (args[index] != null) {
String sign = getSign(args[index], signValidate.signName());
if (StringUtils.isBlank(sign)) {
return CommonResponse.error(SignErrorCode.NON_PARAM);
}
response = verifySign(request, signHeader, sign);
if (!response.isStatus()) {
return response;
}
args[index] = decryptParam(args[index], signValidate.signName(), APP_PASSWORD);
}
return CommonResponse.success(args);
}
/**
* 验签
*
* @param request 请求
* @param signHeader 签名header
* @param parameters 参数
* @return 验签结果
*/
private CommonResponse verifySign(HttpServletRequest request, Map<String, String> signHeader,
String parameters) {
//根据appKey查询
String appSecret = APP_SECRET;
//验签
String method = request.getMethod();
String canonicalURI = request.getServletPath() + request.getPathInfo();
String salt = signHeader.get(headerSalt);
String timestamp = signHeader.get(headerTimestamp);
String appKey = signHeader.get(headerAppKey);
String sign = SignUtil
.generateSign(salt, timestamp, appKey, method, canonicalURI, parameters, appSecret);
if (!Objects.equals(sign, signHeader.get(headerAuthorization))) {
return CommonResponse.error(SignErrorCode.VERIFY_FAIL);
}
return CommonResponse.success();
}
private String getSign(Object signObject, String signName) {
Class<?> resultClass = signObject.getClass();
Field[] fieldInfo = resultClass.getDeclaredFields();
for (Field field : fieldInfo) {
if (signName.equals(field.getName())) {
field.setAccessible(true);
Object fieldValue = null;
try {
fieldValue = field.get(signObject);
if (fieldValue == null) {
return null;
}
return fieldValue.toString();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
break;
}
}
return null;
}
/**
* 解密参数
*
* @param args 入参实体
* @param signName 签名字段名称
* @param appPassword 解密密码
* @return 解密后的参数
*/
private Object decryptParam(Object args, String signName, String appPassword) {
Class<?> resultClass = args.getClass();
Field[] fieldInfo = resultClass.getDeclaredFields();
for (Field field : fieldInfo) {
if (signName.equals(field.getName())) {
field.setAccessible(true);
Object fieldValue = null;
try {
fieldValue = field.get(args);
String decryptValue = SignUtil.decrypt(fieldValue.toString(), appPassword);
field.set(args, decryptValue);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
break;
}
}
return args;
}
}