使用场景:不同系统间当登录或者请求相关接口时校验是否含有AppKey等信息。如果有的话,可以处理相关的业务逻辑,如果没有的话,则返回相应的返回信息,前后端接口相关信息约定好,相关数据可以进行加密。 对相关的接口添加自定义注解,Aop进行方法的增加,对相关自定义注解进行校验。
校验主要是对接口方法中的参数,类型进行校验。对数据进行解密处理,然后调用执行相关接口处理相关业务逻辑。
package com.yl.oms.api.base.annotations.appkey; import com.yl.entity.vo.base.ResultMessage; import com.yl.facade.api.ApiReceiveQueueService; import com.yl.oms.api.util.DESUtil; import com.yl.util.lang.StringUtils; import net.sf.json.JSONObject; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; import java.util.ResourceBundle; /** * APPKey验证类AOP执行调度 * @author Tolk */ @Aspect @Component @Order(100) public class AppKeyValidationAspect { private static Logger logger = LoggerFactory.getLogger(AppKeyValidationAspect.class); @Autowired ApiReceiveQueueService apiReceiveQueueService; /** * Around * 手动控制调用核心业务逻辑,以及调用前和调用后的处理, * 注意:当核心业务抛异常后,立即退出,转向AfterAdvice * 执行完AfterAdvice,再转到ThrowingAdvice * @param pjp * @return * @throws Throwable */ @Around("@annotation(com.yl.oms.api.base.annotations.appkey.AppKeyValidation)") // @Pointcut("execution(public * com.yl.oms.api.controller.cti.AddCtiCallRecordController*add(..)) && @annotation(com.yl.oms.api.base.annotations.appkey.AppKeyValidation)") public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable { Object retVal = null; // String resultStr = null; MethodSignature ms=(MethodSignature) pjp.getSignature(); Method method=ms.getMethod(); // AppKeyValidation appKeyValidation = method.getAnnotation(AppKeyValidation.class); //获取方法Code String methodName = method.getName(); ResultMessage sApiValidationResult = null; String appKey = null; String appApiHash = null; String needEncrypt = null; String sOldParam = null; String sNewParam = null; String secretKeyStr = null; try{ //参数验证 if(pjp.getArgs().length != 3){ sApiValidationResult = new ResultMessage("接口参数异常, 非约定规范(指定的三个参数)! "); }else{ HttpServletRequest request = (HttpServletRequest) pjp.getArgs()[1]; appKey = request.getHeader("Dapi-App-Key"); appApiHash = request.getHeader("Dapi-Hash"); needEncrypt = request.getHeader("Dapi-Encrypt"); sOldParam = (String) pjp.getArgs()[0]; secretKeyStr = appKey; if(appKey != null && appKey.length() < 32){ secretKeyStr = DESUtil.string2MD5(appKey); } if(appKey == null || "".equals(appKey)){ sApiValidationResult = new ResultMessage("AppKey参数验证失败! "); }else if(appApiHash == null || "".equals(appApiHash)){ sApiValidationResult = new ResultMessage("AppApiHash参数验证失败! "); }else{ //验证ApiHash合法性 String sApiHash = DESUtil.string2MD5(appKey + sOldParam); boolean isCheckPass = (sApiHash != null && appApiHash.equals(sApiHash)); //获取config.properties中的配置信息 ResourceBundle.clearCache(); ResourceBundle bundle = ResourceBundle.getBundle("config"); String unCheckAppkeys = StringUtils.safeToString(bundle.getString("appkeys"),"CRM-EHR"); //CRM接口不做hash验证 只验证 appKey = CRM-EHR if(unCheckAppkeys.contains(appKey)){ isCheckPass = true; } if(isCheckPass){ try{ if(needEncrypt != null && "true".equals(needEncrypt)){ sNewParam = DESUtil.decrypt(sOldParam, secretKeyStr); }else{ sNewParam = sOldParam; } pjp.getArgs()[0] = sNewParam; pjp.getArgs()[2] = appKey; try{ //调用执行原代码 retVal = pjp.proceed(pjp.getArgs()); if(retVal == null){ sApiValidationResult = new ResultMessage(true, "成功"); }else if(method.getReturnType() == String.class){ sApiValidationResult = new ResultMessage(true, retVal.toString()); }else if(method.getReturnType() == ResultMessage.class){ sApiValidationResult = (ResultMessage)retVal; } }catch(Exception e){ sApiValidationResult = new ResultMessage("执行API处理失败!Message: " +e.toString()); } }catch(Exception e){ sApiValidationResult = new ResultMessage("参数内容解密失败!"); } }else{ sApiValidationResult = new ResultMessage("AppKey和 参数内容 合法性 验证失败!"); } } } }catch(Exception e){ sApiValidationResult = new ResultMessage("程序异常, 请联系接口研发人员, ErrorMessage: " + e.toString()); logger.error("API方法异常("+methodName+"), 程序执行异常, Message: " + e.toString() ); } if(sApiValidationResult == null){ sApiValidationResult = new ResultMessage("返回值异常,请联系研发人员!"); } //当失败的时候打印参数 if(sApiValidationResult != null && !sApiValidationResult.isSuccess()){ logger.info("invokeError-" + methodName + ", appKey: " + appKey + ", appApiHash: " + appApiHash + ", Result: "+ sApiValidationResult+", Param: " + (sNewParam == null ? sOldParam : sNewParam)); } if(sApiValidationResult != null && secretKeyStr != null && "true".equals(needEncrypt)){ if(method.getReturnType() == String.class){ return DESUtil.encrypt(sApiValidationResult.toString(), secretKeyStr); } } if(method.getReturnType() == String.class){ retVal = sApiValidationResult.toString(); }else if(method.getReturnType() == ResultMessage.class){ retVal = sApiValidationResult; }else if(method.getReturnType() == JSONObject.class){ retVal = JSONObject.fromObject(sApiValidationResult); }else if(method.getReturnType() == void.class){ retVal = null; } return retVal; } }总结:主要是通过自定义注解的使用,AOP面向切面编程思想具体使用,对添加了自定义注解的接口方法的增强。然后处理相关的业务逻辑,这里主要是权限校验,数据解密业务场景的使用。