当前位置: 首页 > news >正文

使用AOP技术实现Java通用接口验签工具

一、背景

在给第三方提供接口时,我们需要对接口进行验签。具体来说,当外部系统调用我们的接口时,请求中需要携带一个签名,我们接收到请求后,会解析数据并校验签名是否正确,以确保请求的合法性和安全性。

为了在不同项目中方便地使用这一功能,我们将签名校验规则封装成一个工具包。使用方只需通过简单的注解即可轻松集成验签功能,无需重复编写验签逻辑,从而提高开发效率并确保一致性。

二、实现原理

  1. 使用AOP来拦截方法
  2. 获取参数值进行组装、校验签名是否一致

三、设计思路

通过俩个注解进行标记所需要进行验签的方法

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SignatureChecker {

    // 服务Code
    String serviceCode() default SignatureConst.EMPTY_STR;

    // 签名生成密钥
    String secretKey() default SignatureConst.EMPTY_STR;

    // 签名过期时间,单位为分钟
    int expireMinutes() default -1;

    // 默认为true,表示需要验证签名
    boolean required() default true;

    // 返回值类型
    String returnType() default SignatureConst.DEFAULT_RETURN_TYPE;

}

serviceCode:服务编码,进行区分不同的服务/业务
secretKey:双方约定好的密钥,进行生成签名,可以写在配置文件中。
expireMinutes:标识签名有效时长,默认5分钟,可以配置文件中进行全局修改。

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface SignatureParam {

    // 0:标识serviceCode 1:标识请求参数
    SignatureParamTypeEnum type() default SignatureParamTypeEnum.PARAMS;

    String requestIdField() default SignatureConst.EMPTY_STR;

    String timestampField() default SignatureConst.EMPTY_STR;

    String signatureField() default SignatureConst.EMPTY_STR;

}

对于不同的请求实体,可能对应的字段名不相同,所以我们需要使用一个注解进行标注当前实体验签字段的名称。

当签名字段发生变化时,可以使用requestIdField、timestampField、signatureField 字段进行指定。

四、代码

4.1 代码结构

4.2 详细代码

4.2.1 SignatureChecker.class
import org.tao.consts.SignatureConst;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SignatureChecker {

    // 服务Code
    String serviceCode() default SignatureConst.EMPTY_STR;

    // 签名生成密钥
    String secretKey() default SignatureConst.EMPTY_STR;

    // 签名过期时间,单位为分钟
    int expireMinutes() default -1;

    // 默认为true,表示需要验证签名
    boolean required() default true;

    // 返回值类型
    String returnType() default SignatureConst.DEFAULT_RETURN_TYPE;

}
4.2.2 SignatureParam.class
import org.tao.consts.SignatureConst;
import org.tao.enums.SignatureParamTypeEnum;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface SignatureParam {

    // 0:标识serviceCode 1:标识请求参数
    SignatureParamTypeEnum type() default SignatureParamTypeEnum.PARAMS;

    String requestIdField() default SignatureConst.EMPTY_STR;

    String timestampField() default SignatureConst.EMPTY_STR;

    String signatureField() default SignatureConst.EMPTY_STR;

}
4.2.3 SignatureAspect.class

import com.alibaba.fastjson2.JSON;
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.stereotype.Component;
import org.springframework.util.StringUtils;
import org.tao.anno.SignatureChecker;
import org.tao.anno.SignatureParam;
import org.tao.config.SignatureProperties;
import org.tao.consts.SignatureConst;
import org.tao.enums.SignatureParamTypeEnum;
import org.tao.exception.SignatureValidationException;
import org.tao.utils.SignatureUtil;

import javax.annotation.Resource;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;

@Aspect
@Component
public class SignatureAspect {
    private static final Logger logger = LoggerFactory.getLogger(SignatureAspect.class);

    @Resource
    private SignatureProperties signatureProperties;

    @Around("@annotation(org.tao.anno.SignatureChecker) " +
            "&& (@annotation(org.springframework.web.bind.annotation.PostMapping) || @annotation(org.springframework.web.bind.annotation.RequestMapping))")
    public Object validateSignature(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        Map<String, Object> paramMap = null;
        String serviceCode = null;
        Object[] args = joinPoint.getArgs();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        SignatureChecker s

相关文章:

  • 【vue】editor富文本输入全英文,谷歌浏览器:元素不会自动换行bug
  • 为什么hash%length 和hashlength-1 的值是一样的(当length=2的幂次方)
  • Java:三十年演进,永续创新的编程传奇
  • 【SPP】蓝牙 SDP 协议在SPP中的互操作性解析
  • vue2修改窗口字典回显
  • 四款高效数据报表工具 让数据分析更简单
  • TCP的连接建立
  • 解释一下Unity碰撞的触发条件
  • 【LeetCode Solutions】LeetCode 121 ~ 125 题解
  • Unity中根据文字数量自适应长宽的对话气泡框UI 会自动换行
  • 助力 Windows 文件管理:重命名与清理重复文件软件精选
  • leetcode刷题日记——罗马数字转整数
  • 基于SpringBoot + HTML 的心理健康管理系统
  • PHY——LAN8720A 代码解析 (三)
  • HttpClient-01.介绍
  • Libevent UDP开发指南
  • 基于动态渲染与反检测技术的爬虫框架设计
  • Spring笔记05-面向切面编程
  • 每日一题(小白)暴力娱乐篇9
  • 【AI4CODE】4 Trae 锤一个数据搬运工的小应用
  • 梅花奖在上海|朱洁静:穿越了人生暴风雨,舞台是最好良药
  • “一节课、两小时”,体育正在回归“C位”
  • 明查|哈佛大学批改美教育部长来信,红笔标出语法错误?
  • 2025中国品牌日上海践行活动启动,将建设品牌生态交互平台
  • 丹麦召见美外交官,强调“不能容忍”美在格陵兰岛间谍活动
  • 咖啡戏剧节举办第五年,上生新所“无店不咖啡,空间皆可戏”