使用注解的方式+AOP校验签名

2021-09-08 14:58:44 浏览数 (1)

1.定义注解 @CheckSign :

代码语言:javascript复制
package com.un.framework.aspectj.lang.openapi;

import java.lang.annotation.*;

/**
 * 校验签名
 *
 * @author shiye
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CheckSign {
    /**
     * 模块
     */
    public String title() default "";

}

2.定义基础请求对象,用来需要检验签名的参数基础类

子类需要继承改方法,并且重写你需要校验签名的参数

代码语言:javascript复制
tranceToStr()
代码语言:javascript复制
package com.un.project.system.domain.other;

import io.swagger.annotations.ApiModelProperty;

import javax.validation.constraints.NotNull;
import java.io.Serializable;

/**
 * @author shiye
 * @create 2021-08-16 13:45
 */
public class BaseRequestParm implements Serializable {

    /**
     * appId
     */
    @ApiModelProperty(value = "appId")
    @NotNull(message = "appId不能为空")
    protected String appId;

    /**
     * 签名
     */
    @ApiModelProperty(value = "签名")
    @NotNull(message = "sign不能为空")
    protected String sign;

    public String getAppId() {
        return appId;
    }

    public void setAppId(String appId) {
        this.appId = appId;
    }

    public String getSign() {
        return sign;
    }

    public void setSign(String sign) {
        this.sign = sign;
    }

    /**
     * 按key的升序排列首尾相接(出了sigin字段)
     * 子类方法需要实现改方法
     * @return
     */
    public String tranceToStr() {
        StringBuffer strBuff = new StringBuffer();
        strBuff.append("appId");
        strBuff.append(appId);
        return strBuff.toString();
    }
}

3. 定义AOP环绕通知拦截信息

代码语言:javascript复制
package com.un.framework.aspectj.lang.openapi;

import com.un.common.utils.security.Md5Utils;
import com.un.project.system.controller.app.BaseResult;
import com.un.project.system.domain.other.BaseRequestParm;
import com.un.project.system.domain.other.CommunityInfoParams;
import com.un.project.system.domain.other.QueryHouseChangeVo;
import com.un.project.system.domain.other.StructAndUserInfoParams;
import org.aspectj.lang.JoinPoint;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * 签名校验处理
 *
 * @author shiye
 */
@Aspect
@Component
public class CheckSignAspect {

    private static final String secret_key = "CRVFSMQA3P2ZKIBU5NOVY9YKH6O1TXPI";
    private static final Logger log = LoggerFactory.getLogger(CheckSignAspect.class);

    /**
     * 配置织入点
     */
    @Pointcut("@annotation(com.un.framework.aspectj.lang.openapi.CheckSign)")
    public void logPointCut() {
    }

    /**
     * 环绕通知
     *
     * @param point 切点
     */
    @Around("logPointCut()")
    public BaseResult doAfterThrowing(ProceedingJoinPoint point) throws Throwable {
        Boolean flag = beforHandleSign(point);
        log.info("签名校验状态: "   flag);
        if (flag == true) {
            return (BaseResult) point.proceed();
        }
        return BaseResult.buildFail("签名校验失败");
    }

    /**
     * 前置通知处理
     *
     * @param joinPoint
     */
    protected Boolean beforHandleSign(ProceedingJoinPoint joinPoint) {
        try {
            /**
             * 获得注解
             */
            CheckSign checkSign = getAnnotationCheckSign(joinPoint);
            if (checkSign == null) {
                return false;
            }
            //获取拦截方法的参数
            Object[] params = joinPoint.getArgs();
            if (params == null || params.length == 0) {
                return false;
            }
            //获取请求参数
            Object obj = params[0];
            //根据不同的请求参数进行验签
            if (obj instanceof BaseRequestParm) {
                BaseRequestParm baseRequestParm = (BaseRequestParm) params[0];
                if (baseRequestParm == null) {
                    return false;
                }
                String tranceToStr = baseRequestParm.tranceToStr();
                String beforSign = secret_key   tranceToStr   secret_key;
                String sign = Md5Utils.hash(beforSign).toUpperCase();
                log.info(" ==== 本系统加签值 ==== "   sign);
                if (sign != null && sign.equals(baseRequestParm.getSign().toUpperCase())) {
                    return true;
                }
            }

        } catch (Exception exp) {
            // 记录本地异常日志
            log.error("==前置通知异常==");
            log.error("异常信息:{}", exp.getMessage());
            exp.printStackTrace();
        }
        return false;
    }

    /**
     * 是否存在注解,如果存在就获取
     */
    private CheckSign getAnnotationCheckSign(JoinPoint joinPoint) throws Exception {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();

        if (method != null) {
            return method.getAnnotation(CheckSign.class);
        }
        return null;
    }

    /**
     * 判断是否需要过滤的对象。
     *
     * @param o 对象信息。
     * @return 如果是需要过滤的对象,则返回true;否则返回false。
     */
    public boolean isFilterObject(final Object o) {
        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;
    }
}

4.调用方式 (只需要一行代码就可以轻轻松松的进行拦截,想拦截哪就拦截哪) : @CheckSign(title = "****")

代码语言:javascript复制
    @PostMapping("/changeData")
    @CheckSign(title = "****")
    public BaseResult<HouseChangeDto> changeData(@RequestBody @Validated QueryHouseChangeVo queryHouseChangeVo) {
        
        return null;
    }

0 人点赞