key和sign的校验可以采用类似日志的切面方式(一个切点可以织入多种通知,例如即织入日志通知,又织入key校验通知)
切面基本思路是定义切点(截点),在切点(截点)处织入通知(前置通知,环绕通知,后置通知)
请求系统在业务数据之后加上key,sign,到达目标系统之后,目标系统用切面拦截(前置通知),校验key(和本地存的是否一致)和sign(加密方式,参数是否一致),通过之后remove掉key,sign留下业务数据(参数操作基于对象引用
,所以后传有效)自动从截点方法继续执行,不通过抛异常(环绕通知需要在通知处手动调用截点方法)
前置通知://不需要手动调用截点,自动运行
截点:
/**
* 所有controller
*/
@Pointcut("execution(* com.houbank.bank.*.controller..*.*(..))")
private void allController() {
}
通知
@Before(value = "allController()" +
"&&!callbackController()" +
"&&!taskController()" +
"&&!webController()" +
"&&!baseController()" +
"&&!nosignController()")
public void req(JoinPoint joinPoint) throws Throwable {
if(joinPoint.getArgs().length > 0){
Object jsonObject = (Object) joinPoint.getArgs()[0];
Map
String key = (String) bodyMap.get("key");
String sign = (String) bodyMap.get("sign");
if (StringUtils.isBlank(key) || StringUtils.isBlank(sign)) {
throw new ParamException("请检查参数key,sign");
}
String secret = null;
String[] split = appKey.split(";");
for (String str : split) {
if (str.split(",")[0].trim().equals(key)) {
secret = str.split(",")[1].trim();
if (logger.isDebugEnabled()) {
logger.debug("对方key=" + key + ",获取的秘钥secret=" + secret);
}
}
}
if (StringUtils.isBlank(secret)) {
logger.error("秘钥为空,对方key=" + key + ",我方appKey集合=" + appKey);
throw new ParamException("key不匹配");
} else {
bodyMap.remove("sign");
bodyMap.remove("key");
if (!SignUtils.signOuter(bodyMap, secret,sign)) {
throw new ParamException(CodeEnum.CODE_9998.getMsg());
}
}
}
}
环绕通知://环绕通知需要手动调用截点
/**
* 执行controller时调用
*/
@Pointcut("execution(* com.houbank.bank.*.controller..*.*(..))")
private void executeController() {
}
@Around("executeController()")
public Object notifyCreditAccountStatusFail(ProceedingJoinPoint joinPoint) throws Throwable {
if(joinPoint.getArgs().length > 0){
Object jsonObject = (Object) joinPoint.getArgs()[0];
Map
String applyNo = null;
if (!map.isEmpty()) {
applyNo = (String) map.get("applyNo");
MDC.put(ApiLogConst.REQUESTIP, request.getServerName());
MDC.put(ApiLogConst.REQUESTPORT, String.valueOf(request.getServerPort()));
MDC.put(ApiLogConst.REQUESTURI, request.getRequestURI());
MDC.put(ApiLogConst.REQUESTTYPE, request.getMethod());
MDC.put(ApiLogConst.APPLYNO, applyNo);
}
LogFactory.setTxId(String.format("applyNo:%s",applyNo));
}
try {
Object obj = super.logMethodArgsReturn(joinPoint); //环绕通知需要手动调用截点
return obj;
} finally {
MDC.remove(ApiLogConst.REQUESTIP);
MDC.remove(ApiLogConst.REQUESTPORT);
MDC.remove(ApiLogConst.REQUESTURI);
MDC.remove(ApiLogConst.REQUESTTYPE);
MDC.remove(ApiLogConst.APPLYNO);
LogFactory.destory();
}
}
发起方:
@Test
public void updateStatus() throws Exception {
String url="http://localhost:8080/bank-gateway/approval/update";
JSONObject jsonObj = new JSONObject();
jsonObj.put("id", "1");
jsonObj.put("status", "0");
Map map=JSONObject.parseObject(jsonObj.toJSONString());
jsonObj.put("key", "bankApi"); //相当于盐值
jsonObj.put("sign",SignUtils.signOuter(map,"a6e237fc-5a53-4e29-a961-813de44a9929")); //相当于加密密码
String resultStr = HttpClientUtil.httpJsonPost(url, jsonObj.toString());
System.out.println(resultStr);
}
接收方:(用上面的前置通知对比key,sign)
/**
* 更新
* @param
* @return
*/
@RequestMapping("update")
public ApiResponse update(@Valid @RequestBody ApprovalRule appRule, Errors errors) throws Exception {
try {
if (approvalRuleMapper.updateByPrimaryKeySelective(appRule)<1){
LOGGER.error(CodeEnum.CODE_9997.getMsg()+"参数:"+appRule.toString());
return ApiResponse.error(CodeEnum.CODE_0001);
}
return ApiResponse.error(CodeEnum.CODE_0000);
} catch (Exception e) {
LOGGER.error("更新rule异常,参数:"+appRule.toString());
return ApiResponse.error(CodeEnum.CODE_9999);
}
}