提供三方API接口、调用第三方接口API接口、模拟API接口(三)使用AOP切面编程实现signature签名验证

news2024/10/1 12:13:52

接着第一篇文章
提供三方API接口、调用第三方接口API接口、模拟API接口(一)通过signature签名验证,避免参数恶意修改
我们来继续优化:

/**
     * 模拟后端校验签名
     * @param request
     * @param data
     * @return
     * @throws UnsupportedEncodingException
     */
    @GetMapping("/sign/verifySign")
    public boolean verifySign(HttpServletRequest request, @RequestParam Map<String, String> data) throws UnsupportedEncodingException {
        String sign = request.getHeader("sign");
        String signType = request.getHeader("sign_type");
        return ApiUtil.verifySign(data, sign, signType);
    }

背景:看这块代码,第一篇中的签名验证是在请求的业务逻辑中手动去调用进行signature验证的。这样代码显得太臃肿,因此采用注解与aop拦截的方式来实现参数校验,复用代码的同时,让程序变得简洁与高效。

接下来先通过AOP实现参数签名校验;

封装请求常量类

package com.atguigu.signcenter.constant;

/**
 *
 * 请求参数常量类
 * @author: jd
 * @create: 2024-08-04
 */
public class ReqParameterConstant {

    /**
     * 请求中的参数类型是head 头部参数的
     */
    public static final  String HEAD ="head";

    /**
     * 请求中的参数类型是form,是表单类型的
     */
    public static final  String FORM ="form";

}

自定义签名校验注解

package com.atguigu.signcenter.annotation;


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

@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface VerifySign {

    /**
     * 参数类型 head 、 form
     */
    String type();
}

aop拦截器

package com.atguigu.signcenter.component;

import com.atguigu.signcenter.annotation.VerifySign;
import com.atguigu.signcenter.constant.ReqParameterConstant;
import com.atguigu.signcenter.util.ApiUtil;
import com.sun.deploy.association.utility.AppUtility;
import io.swagger.annotations.Extension;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * 切面类
 * 先定义一个切面,这个切面主要的针对于controller中的所有方法,
 * 再顶定义一个环绕通知,这个环绕通知主要是为了判断是否有自定义注解,@VerifySign ,如果有自定义注解的话,则会做一些业务处理、逻辑校验
 * @author: jd
 * @create: 2024-08-04
 */

@Aspect
@Slf4j
@Component
public class VerifySignAop {


    /**
     * 定义一个切面方法, 使用 AOP 的环绕通知去拦截这里标明的所有访问,拦截的是 controller 层中的所有的public方法,任何参数都可
     */
    @Pointcut("execution(public * com.atguigu.signcenter.controller.*.*(..)))")
    public  void myPointCut(){

    }


    /**
     * 环绕通知,主要用于判断对于切面方法中是否有某个注解,如果有的话,则做逻辑校验或者某些业务逻辑的处理
     * @return
     */
    @Around("myPointCut()")
    @Synchronized
    public Object aroundAOP(ProceedingJoinPoint joinPoint) throws Throwable {
        //获得getSignature方法对象
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        // 判断方法上是否有注解 @VerifySign
        VerifySign  verifySign = methodSignature.getMethod().getDeclaredAnnotation(VerifySign.class);
        //定义两个变量用于,接收参数签名字符串和参数签名的加密方式字符串
        String sign = null;
        String signType = null;
        if(null!=verifySign){
            // 获取上下文的请求
            HttpServletRequest request = getRequest();
            String type = verifySign.type();
            log.info("type:{} " + type);
            if(ReqParameterConstant.HEAD.equals(type)){
                sign =  request.getHeader("sign");
                signType = request.getHeader("sign_type");
            }

            if(ReqParameterConstant.FORM.equals(type)){
                sign = request.getParameter("sign");
                signType = request.getParameter("sign_type");
            }
            if(StringUtils.isBlank(sign)){
                response("该请求无签名!");
                return null;
            }
            if(StringUtils.isBlank(signType)||!"RSA".equals(signType)){
                response("无签名加密方式|签名加密方式不是RSA,所以不支持!");
                return null;
            }
            log.info("sign:{} " , sign);
            // 获取请求的所有参数 ,并将他形成一个HashMap,为了参数验证构建
            Map<String, String> data = new HashMap();
            Enumeration<String> parameterNames = request.getParameterNames();
            while (parameterNames.hasMoreElements()){
                String element = parameterNames.nextElement();
                data.put(element,request.getParameter(element));
            }
            //参数验签
            boolean verifyFlag = ApiUtil.verifySign(data, sign, signType);
            if (!verifyFlag) {
                response("无效的签名!");
                return null;
            } else {
                log.info("有效的签名。");
            }


        }
        //程序继续向下执行
        Object proceed = joinPoint.proceed();
        return proceed;


    }




    /**
     *
     * 获取容器上下文请求
     * @return
     */
    public HttpServletRequest getRequest() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        return request;
    }


    /**
     * 响应错误响应信息
     * @param msg
     */
    public void response(String msg) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = requestAttributes.getResponse();
        response.setHeader("Content-type", "text/html;charset=UTF-8");
        try(PrintWriter writer = response.getWriter()) {
            writer.println(msg);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }




}

控制器的业务方法添加签名校验注解


    @VerifySign(type = "head")
    @GetMapping("sign/testAnnotation")
    @ResponseBody
    public String test(@RequestParam Map<String,String> data){
        // 模拟业务逻辑
        // TODO Something
        log.info("做一些业务,业务模拟");
        return "成功通过AOP切面中的校验,执行了业务逻辑";
    }

测试
需要携带上参数,不然有签名没用,因为签名就是为了验证参数是否发生了变化
参数不带签名时候:
http://localhost:8025/sign/testAnnotation?name=zhangsan&age=100
在这里插入图片描述
可以看到,验证提示 该请求无签名! ,而且也没有打印controller中模拟业务的代码(“做一些业务,业务模拟”)。

携带上签名参数
在这里插入图片描述

测试结果:
在这里插入图片描述

IDEA控制台打印结果:
在这里插入图片描述
至此完成了,AOP实现签名验证的代码实现。

码字不易,不足之处还请大家多多指教~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1979631.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[环境配置]C4D OC渲染器解决缺少cudnn_8_0_4Octance正版缺少cudnn_8_0_4_win文件解决方法

关于Octance正版缺少cudnn_8_0_4_win文件解决方法 可在此处https://download.csdn.net/download/FL1623863129/89605383进行下载 放到对应文件位置即可 在计算机图形学领域&#xff0c;Cinema 4D&#xff08;C4D&#xff09;作为一款顶尖的专业3D建模、动画与渲染软件&#x…

学生管理系统之数据模拟与数据显示

学生管理系统之数据模拟与数据显示 设计一个单例 模拟数据 显示数据

CSP-J 2022 填程题19.解析

19. &#xff08;枚举因数&#xff09;从小到大打印正整数 n 的所有正因数。 试补全枚举程序。 01 #include <bits/stdc.h> 02 using namespace std; 03 04 int main() { 05 int n; 06 cin >> n; 07 08 vector<int> fac; 09 fac.reserve((int)ce…

【算法】动态规划---多态dp问题

多态dp问题 一.[leetcode] (打家劫舍I) 17.16.按摩师二. [leetcode] 213. 打家劫舍 II三.[leetcode] 740. 删除并获得点数四.[leetcode] LCR 091. 粉刷房子五.[leetcode] 309. 买卖股票的最佳时机含冷冻期六.[leetcode] 714. 买卖股票的最佳时机含手续费七.[leetcode] 123. 买卖…

职场,要想逆袭,必须要“装”

普通人&#xff0c;没有家庭背景&#xff0c;没有社会资源&#xff0c;没有好学历&#xff0c;如何才能逆袭呢&#xff1f;有朝一日自己熬出头&#xff0c;又如何避免被别人针对呢&#xff1f; 最重要的就是要会“装”。 在社会上&#xff0c;只有资源多的人才能更好的生存&a…

opencv c++ python等比缩小或放大显示图片代码

c代码&#xff0c;其中scale_percent用来设置百分比&#xff0c;例如50 就是百分之五十&#xff0c;也就是一半的大小&#xff0c;当然也可以设置成200&#xff0c;相当于原来的2倍大小&#xff0c;注意图片路径换成实际路径。 #include <opencv2/opencv.hpp>int main()…

【Java零基础视频教程】综合练习题(一)——基础练习

文章目录 基础练习飞机票打印素数生成验证码复制数组评委打分数字加密抽奖双色球 基础练习 飞机票 机票价格按照淡季旺季、头等舱和经济舱收费、输入机票原价、月份和头等舱或经济舱。 ​ 按照如下规则计算机票价格&#xff1a;旺季&#xff08;5-10月&#xff09;头等舱9折&…

pxe安装部署

RHEL7为例&#xff1a; ifconfig查看ip 一.环境配置 1.配置软件仓库&#xff1a; mkdir /rhel7 mount /dev/cdrom /rhel7 echo mount /dev/cdrom /rhel74 >> /etc/rc.d/rc,local chmod x /etc/rc.d/rc.local 2.关闭火墙和selinux&#xff0c;下载…

【极速前进】20240706-24240714:用于Agent的树搜、理解LLM的语种困惑、事实知识抽取微调、Quiet-STaR

相关博客 【极速前进】20240706-24240714&#xff1a;用于Agent的树搜、理解LLM的语种困惑、事实知识抽取微调、Quiet-STaR 【极速前进】20240615-20240623&#xff1a;Zipper融合模态、VideoLLM视频理解、WebAgent可以自我改善、Nemotron-4、AnyGPT统一模态 【极速前进】20240…

Final Shell for Mac 虚拟机连接工具【简单易操作,轻松上手】【开发所需连接工具】

Mac分享吧 文章目录 效果一、下载软件二、安装软件三、运行测试安装完成&#xff01;&#xff01;&#xff01; 效果 一、下载软件 下载软件 链接&#xff1a;http://www.macfxb.cn 二、安装软件 三、运行测试 安装完成&#xff01;&#xff01;&#xff01;

Kubernets(k8s) 网络原理三:同主机内Pod相互访问

前两篇文章中我们介绍了pod怎么和宿主机通信以及pod怎么访问外网&#xff0c;这两种通信是理解pod间通信的基础。 关于pod间的相互访问&#xff0c;这里还需要细化一下。回想一下pod在k8s节点中的分布&#xff0c;两个pod可能分布在同一台宿主机上&#xff0c;也可能分布在不同…

可视化图表与页面源代码显示

可视化图表与页面源代码显示 页面效果&#xff1a; <!DOCTYPE html> <html lang"en" style"height: 100%"> <head><meta charset"utf-8"><title>饼状图</title><style>body {display: flex;height:…

基于51单片机的交通信号灯proteus仿真设计

1.功能简介 交通信号灯是一种经典应用电路&#xff0c;本设计基于51单片机&#xff0c;利用Proteus仿真软件构建了一个模拟交通信号灯系统。该系统能够模拟真实交通环境中的信号变化&#xff0c;包括红灯、黄灯和绿灯的切换&#xff0c;以及倒计时显示等功能&#xff0c;各种灯…

谷歌出品,一款免费的智能绘图工具

AutoDraw是由Google开发的一款基于网络的智能绘图工具&#xff0c;旨在通过人工智能技术帮助用户快速、简便地创建图画和图表。该工具于2017年4月11日由谷歌创意实验室推出&#xff0c;并迅速获得了广泛关注。 AutoDraw的核心功能是利用机器学习算法识别用户的草图或涂鸦&…

C++STL专题-string类

目录 1.标准库中的string类 1.1 string类 2.2 auto和范围for 2.2.1 auto关键字 2.2.2 范围for 2.3 string类的常用接口讲解 1.string类对象的常见构造 2.元素访问 3.迭代器(iterator) 3.1 begin 和 end 3.2 rbegin 和 rend 4.容器 5.修改 5.1 append 5.2 assign…

在C#中为图片添加数字水印的几种办法

最近在写个人项目时&#xff0c;有遇到需要将图片加上水印防止被盗取的需求。这里找了几种实现方式&#xff0c;可供有需要的朋友参考。 本身我不是搞算法这块的&#xff0c;所以这里只是找了一些实现&#xff0c;也没有继续深究下去。 以前在学校的时候从书上了解过可以将一…

cmake常用命令学习

1.include https://blog.csdn.net/qq_38410730/article/details/102677143 CmakeLists.txt才是cmake的正统文件&#xff0c;而.cmake文件是一个模块文件&#xff0c;可以被include到CMakeLists.txt中。 include指令一般用于语句的复用&#xff0c;也就是说&#xff0c;如果有…

OBS Studio:如何打造专业级的视频直播体验

1.简介 OBS&#xff08;Open Broadcaster Software&#xff09;是一款开源的视频录制和直播软件&#xff0c;广泛用于视频制作、游戏直播和网络直播。它支持多种操作系统&#xff0c;包括Windows、macOS和Linux。OBS提供了丰富的功能&#xff0c;包括但不限于&#xff1a; **…

聊聊跨境电商平台与固定IP的那些事

IP地址网络地址&#xff08;网络号&#xff09;主机地址&#xff08;地址号&#xff09;&#xff0c;IP地址是一台电脑在网络中的唯一标识&#xff0c;可分为固定IP与动态IP。那么IP地址的分类有哪些&#xff1f;什么IP适合亚马逊/eBay/速卖通等平台运营时使用&#xff1f; A类…

Spring5 的日志学习

我们在使用 Spring5 的过程中会出现这样的现像&#xff0c;就是 Spring5 内部代码打印的日志和我们自己的业务代码打印日志使用的不是统一日志实现&#xff0c;尤其是在项目启动的时候&#xff0c;Spring5 的内部日志使用的是 log4j2&#xff0c;但是业务代码打印使用的可能是 …