MemoryAPI 开发者文档 MemoryAPI 开发者文档
首页
    • 概述
    • 系统设计
    • 维护升级
    • 多元 API 生态
    • 高效 SDK 集成
    • 实时流量监控
    • 资源集中治理
    • 个人信息管理
    • 内容概览
    • Ant Design Pro 脚手架
    • OpenAPI 生成接口
    • Vuepress 静态文档站点
    • 基础信息管理
    • 丰富的接口服务
    • 高校 SDK 集成
    • Maven 聚合工程
    • Nacos 注册中心
    • Gateway 网关
    • 远程服务调用
    • API 签名认证
    • JWT 认证授权
    • Dubbo 容器部署
    • 其他核心功能
    • 定制 Spring Boot 初始模板
    • 全局业务逻辑梳理
  • 简介
  • 常见问题与解答
首页
    • 概述
    • 系统设计
    • 维护升级
    • 多元 API 生态
    • 高效 SDK 集成
    • 实时流量监控
    • 资源集中治理
    • 个人信息管理
    • 内容概览
    • Ant Design Pro 脚手架
    • OpenAPI 生成接口
    • Vuepress 静态文档站点
    • 基础信息管理
    • 丰富的接口服务
    • 高校 SDK 集成
    • Maven 聚合工程
    • Nacos 注册中心
    • Gateway 网关
    • 远程服务调用
    • API 签名认证
    • JWT 认证授权
    • Dubbo 容器部署
    • 其他核心功能
    • 定制 Spring Boot 初始模板
    • 全局业务逻辑梳理
  • 简介
  • 常见问题与解答
  • 内容概览

    • 概览
  • 前端

    • Ant Design Pro 脚手架
    • OpenAPI 生成接口
    • Vuepress 静态文档站点
  • 后端

    • 基础信息管理
    • 丰富的接口服务
    • 高效 SDK 集成
    • Maven 聚合工程
    • Nacos 注册中心
    • Gateway 网关
    • 远程服务调用
    • API 签名认证
      • 🍜 需求分析
      • 🍚 API 签名认证
        • 原理
        • 防止篡改,完整性
        • 身份认证,真实性
        • 编码实现
        • 密钥对生成
        • 签名生成
        • 签名携带
        • 发送请求
        • 签名验证
    • JWT 认证授权
    • Dubbo 容器部署
    • 其他核心功能
    • 定制 Spring Boot 初始模板
    • 全局业务逻辑梳理
目录

API 签名认证

学习目标

在这里,你将系统学习了解 API 签名认证的具体代码实现

我们将以最简单直接的方式为您呈现内容!

# 🍜 需求分析

  • 我们已经自主设计了丰富的接口,可以根据用户请求提供丰富的接口服务。那么当用户发起一次接口调用请求之后,我们应该如何妥善处理这个请求,才能保证这次接口调用的完整性和安全性呢?

  • 我们希望实现这样的业务逻辑:

    • 每一个在 MemoryAPI 忆汇廊 注册过的用户,系统都会为其发放唯一的密钥,用户可以发起接口调用请求时必须携带密钥

    • 服务端在接收到用户的接口调用请求之后,需要根据该请求中携带的密钥,来判断该用户是否有权限享受接口调用服务。

    • 对于携带密钥的校验,可以从很多方面着手考虑:密钥是否正确、如何确保密钥的完整性等等,这都是判断该用户能否成功调用接口的重要依据

    • 当然,除了以上校验密钥的核心逻辑,一次完整的接口调用业务逻辑判断还应该有:该用户是否存在、所调用的接口是否存在或者是否上线、给用户分配的调用次数是否耗光等等,这样的校验逻辑很大程度上能使整个接口调用流程更加完善,目前不做考虑。

# 🍚 API 签名认证

🍖 推荐阅读:网络传输安全 (opens new window)

# 原理

  • API 签名认证的原理是通过使用密钥对请求进行签名,以验证请求的来源和完整性。目标是确保只有拥有正确密钥的请求才能通过验证,防止未经授权的访问和使用,以及检测数据篡改。

# 防止篡改,完整性

  • 摘要算法:一种特殊的单向加密的压缩算法,它能够把任意长度的数据“压缩”成固定长度、而且独一无二的“摘要”字符串,就好像是给这段数据生成了一个数字“指纹”。摘要和原数据是完全等价的,加密后的数据无法解密,不能从摘要逆推出原文。

  • 发送方把加密后的数据,使用摘要算法生成摘要,把加密数据和该摘要一同发往接收方。接收方使用同样的摘要算法对加密数据进行计算,比照生成的摘要和接受的摘要是否一致,保证了通信数据的完整性。

# 身份认证,真实性

  • 数字签名:发送方要保证通信数据是真实可信的,不是别人伪造的。使用自己的私钥对摘要加密,生成数字签名。数字签名和加密数据被一同发往接收方。

  • 接收方使用发送方的公钥解密,验证签名,拿到摘要,再比对原数据验证完整性。这样就可以像签署文件一样,证明消息确实是发送方发的。

# 编码实现

  • 我们使用 Java 编程语言,实现了根据 API 签名认证机制来验证用户请求。它通过验证用户请求中的签名,确保请求的合法性和完整性,从而决定是否允许该请求成功调用 API。

# 密钥对生成

  • 这一点在前面提到过:每一个在 MemoryAPI 忆汇廊注册过的用户,系统都会为其发放唯一的密钥,用户可以发起接口调用请求时必须携带密钥

  • 我们给用户分配一个密钥对:accessKey 和 secretKey,即公钥和私钥

private String accessKey = "memory";

private String secretKey = "12345678";

# 签名生成

  • 该方法使用 SHA256 摘要算法生成签名。它首先将请求体和私钥拼接在一起,然后使用 Digester 类的 SHA256 实例对拼接后的内容进行摘要计算,最后返回生成的签名:
/**
  * 生成签名
  *
  * @param body 请求体
  * @param secretKey 私钥
  * @return 签名
  */
public static String getSign(String body, String secretKey) {
    Digester md5 = new Digester(DigestAlgorithm.SHA256);
    String content = body + "." + secretKey;

    // 使用 SHA256 摘要算法生成签名
    return md5.digestHex(content);
}

# 签名携带

  • 功能:根据请求体 body,构建一个包含签名的头部信息映射,该方法返回一个包含特定键值对的 HashMap。
/**
  * 构建一个包含签名的头部信息映射
  *
  * @param body 请求体
  * @return 包含特定键值对的 HashMap
  */
public Map<String, String> getHeaderMap(String body) {
    Map<String, String> hashMap = new HashMap<>();
    hashMap.put("accessKey", accessKey);
    hashMap.put("nonce", RandomUtil.randomNumbers(4));
    hashMap.put("body", body);
    hashMap.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
    hashMap.put("sign", getSign(body, secretKey));

    return hashMap;
}
  • 这个方法的目的是构建一个包含特定头部字段的 Map 对象,用于 HTTP 请求头,其中包含一些验证信息以确保请求的完整性和来源。下面是对这些头部字段的详细解释:
    • accessKey: 为用户分配的唯一的密钥,用于验证发送请求的实体是否被授权。
    • nonce: 是一个随机生成的字符串或数字,用于防止重放攻击。
    • body: 请求的主要内容。
    • timestamp: 表示当前时间的 Unix 时间戳,用于验证请求是否在合理的时间内发送。
    • sign: 这是一个使用私钥对消息进行加密的结果,验证消息来源,确保消息未被篡改。

# 发送请求

  • 携带请求数据和签名,通过 POST 请求向指定的 URL 发送请求:
/**
  * 复读机
  *
  * @param user 用户名
  * @return 返回用户名
  */
public String getUserByPost(User user) {
    String json = JSONUtil.toJsonStr(user);

    return HttpRequest.post(GATEWAY_HOST + "/api/name/user")
            .addHeaders(getHeaderMap(json))
            .body(json)
            .execute()
            .body();
}

# 签名验证

  • 接口提供方收到调用请求,获取数据和签名 sign,用一致的摘要算法生成签名 serverSign,比较两个签名是否一致,即可判断在请求过程中数据有没有被篡改,提升了安全性(以下省略其他请求参数的校验)
@PostMapping("/user")
public String getUserNameByPost(@RequestBody User user, HttpServletRequest request) {
    String accessKey = request.getHeader("accessKey");
    String nonce = request.getHeader("nonce");
    String timestamp = request.getHeader("timestamp");
    String body = request.getHeader("body");
    String sign = request.getHeader("sign");

    ................................

    String serverSign = SignUtils.getSign(body, secretKey);

    if (sign == null || !sign.equals(serverSign)) {
        return handleNoAuth(response);
    }

    return "POST 我的名字是: " + user.getName();
}
  • 至此,我们实现了根据 API 签名认证机制,判断用户请求能否成功地调用相应的接口服务
远程服务调用
JWT 认证授权

← 远程服务调用 JWT 认证授权→

Theme by Vdoing | Copyright © 2023-2024 回忆如初
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式