项目总结 鱼皮 API 开放平台项目

前言

项目来源

学习程序员鱼皮API 开放平台项目开源项目:https://github.com/liyupi/yuapi-backend-public

以后端为主

技术选型

前端
  • React 18
  • Ant Design Pro 5.x 脚手架
  • Ant Design & Procomponents 组件库
  • Umi 4 前端框架
  • OpenAPI 前端代码生成
后端
  • Java Spring Boot
  • MySQL 数据库
  • MyBatis-Plus 及 MyBatis X 自动生成
  • API 签名认证(Http 调用)
  • Spring Boot Starter(SDK 开发)
  • Dubbo 分布式(RPC、Nacos)
  • Swagger + Knife4j 接口文档生成
  • Spring Cloud Gateway 微服务网关
  • Hutool、Apache Common Utils、Gson 等工具库

需求分析

建立一套按次计费,提供接口调用服务的 API 开放平台

用例分析

用例图

API 开放平台用例图

用例描述
  • 平台管理员
    • 上线接口:管理员可以将开发完成的接口上线,使其可供接口使用者调用。
    • 下线接口:管理员可以将某个接口下线,即停止该接口的调用。
    • 管理接口:
      • 增:管理员可以添加新的接口到平台,包括接口名称、接口描述、接口URL等信息。
      • 删:管理员可以删除平台上的某个接口。
      • 改:管理员可以修改接口的信息,如接口名称、接口描述、接口URL等。
      • 查:管理员可以查看平台上所有接口的信息,包括接口名称、接口描述、接口URL等。
    • 发布接口:管理员可以发布开发完成的接口,以供接口使用者调用。
    • 测试接口:管理员可以对接口进行测试,以确保其功能的正确性和稳定性。
  • 接口使用者
    • 浏览接口:使用者可以浏览平台上的所有接口,包括接口名称、接口描述、接口URL等信息。
    • 开通接口:使用者可以开通某个接口,使其可供自己调用。
    • 调用接口:使用者可以通过接口URL调用已开通的接口,向其发送请求并获取响应。

系统设计

架构图

API 开放平台架构图

数据库设计

用户信息表
字段名称 数据类型 允许为空 默认值 注释
id bigint NO id
userName varchar(256) YES 用户昵称
userAccount varchar(256) NO 账号
userAvatar varchar(1024) YES 用户头像
gender tinyint YES 性别
userRole varchar(256) NO user 用户角色:user / admin
userPassword varchar(512) NO 密码
accessKey varchar(512) NO accessKey
secretKey varchar(512) NO secretKey
createTime datetime NO 创建时间
updateTime datetime NO 更新时间
isDelete tinyint NO 0 是否删除(0-未删, 1-已删)
接口信息表
字段名称 数据类型 允许为空 默认值 描述
id bigint 主键
name varchar 接口名称
description varchar 接口描述
url varchar 接口地址
requestParams text 请求参数
requestHeader text 请求头
responseHeader text 响应头
status int 0 接口状态(0-关闭,1-开启)
method varchar 请求类型
userId bigint 创建人
createTime datetime 当前时间 创建时间
updateTime datetime 当前时间,自动更新 更新时间
isDelete tinyint 0 是否删除(0-未删,1-已删)
调用信息表
字段名称 数据类型 允许为空 默认值 注释
id bigint 主键
userId bigint 调用用户 id
interfaceInfoId bigint 接口 id
totalNum int 0 总调用次数
leftNum int 0 剩余调用次数
status int 0 状态(0-正常,1-禁用)
createTime datetime 当前时间 创建时间
updateTime datetime 当前时间,自动更新 更新时间
isDelete tinyint 0 是否删除(0-未删,1-已删)

子项目设计

api-frontend(React 项目)
功能介绍
  • 后台管理页面
    • 发布接口:管理员可以在后台管理页面上发布新的接口。该功能需要填写接口的基本信息(名称、描述、接口类型、参数等),并上传接口文档和示例。
    • 下线接口:管理员可以在后台管理页面上下线已发布的接口,即停止对外提供接口服务。
    • 管理接口:管理员可以在后台管理页面上进行接口的增加、删除、修改和查询操作。这些操作包括对接口的基本信息、参数、接口文档等进行管理。
    • 统计分析:管理员可以在后台管理页面上查看接口的使用统计数据和分析报表,包括接口调用次数、调用者数量、调用时间等。
  • 用户前台
    • 浏览接口:用户可以在前台浏览已发布的接口列表,查看接口的基本信息和示例。
    • 开通接口:用户可以在前台开通需要使用的接口,输入相应的参数并完成支付操作。
    • 调用接口:用户可以在前台使用已开通的接口,输入相应的参数进行调用,并获取接口返回的结果。
api-gateway(Spring Boot 项目)
功能介绍
  • 日志记录:网关需要记录所有经过的请求和响应信息,包括请求方法、URL、请求头、请求体、响应状态码、响应头、响应体等。这些日志信息用于后续的分析、监控和故障排查。
  • 跨域处理:当客户端从一个域名访问另一个域名的接口时,由于浏览器的同源策略限制,会拒绝跨域请求。网关可以拦截跨域请求,在请求或响应头中添加跨域相关的头信息,如Access-Control-Allow-OriginAccess-Control-Allow-Methods等,以允许跨域请求的执行。
  • 流量转发:本质上是跳板,可以将请求转发到后端的不同服务。通过这种方式实现请求的路由功能。
    • 将信息管理请求转发到api-backend服务
    • 将接口调用请求转发到api-interface服务
  • 流量染色:为了区分由网关处理的请求,网关可以在响应头中添加特定的标识,如X-Gateway-Origin: gateway。这样,当客户端收到响应时,可以根据这个标识知道该响应来自网关。
  • 统计次数:网关可以记录每个接口调用的次数,使用数据库来存储这些信息。当接口调用请求经过网关时,网关会更新相应接口的计数器,并将其保存到数据库中。这样可以方便统计和监控接口的使用情况。
依赖管理
  • spring-boot-starter:基础的 Spring Boot 框架依赖。
  • spring-boot-starter-test:用于在测试中集成Spring Boot的依赖。
  • spring-cloud-starter-gateway:Spring Cloud Gateway 服务网关
  • api-common:自定义的公共 API 模块。
  • api-client-sdk:自定义的 API 客户端 SDK 模块。
  • dubbo-spring-boot-starter:基于 Spring Boot 的 Dubbo 框架依赖,用于构建和部署 Dubbo 应用。
  • dubbo-registry-nacos:Dubbo 的 Nacos 注册中心依赖,用于将 Dubbo 服务注册到 Nacos 中心,并实现服务的发现和路由。
<dependencies>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
        <version>3.1.3</version>
    </dependency>

    <dependency>
        <groupId>org.example</groupId>
        <artifactId>api-common</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>

    <dependency>
        <groupId>org.example</groupId>
        <artifactId>api-client-sdk</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>3.0.9</version>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-registry-nacos</artifactId>
        <version>3.0.9</version>
    </dependency>

</dependencies>
api-backend(Spring Boot 项目)
功能介绍
  • 用户中心
    • 登录注册:实现用户的身份验证、用户信息存储(其中密码加密存储)、accessKey- secretsKey 分配
    • 用户增删改查:向数据库增加、删除、修改、查询用户信息
  • 接口信息管理
    • 接口增删改查:向数据库增加、删除、修改、查询接口信息
    • 调用信息增删改查:向数据库增加、删除、修改、查询接口调用信息
      相当于付费模块,为用户分配可使用的接口以及使用次数
依赖管理
  • spring-boot-starter:基础的 Spring Boot 框架依赖。
  • mysql-connector-j:MySQL 数据库的 Java 连接器,用于在 Spring Boot 应用程序中连接和操作 MySQL 数据库。
  • lombok:简化Java代码的注解库,自动生成样板代码(如Getter、Setter、toString 等),减少开发工作量。
  • spring-boot-starter-test:用于编写单元测试和集成测试的Spring Boot测试框架。
  • mybatis-spring-boot-starter-test:针对MyBatis的Spring Boot测试工具,可以方便地进行MyBatis Mapper和XML的单元测试。
  • commons-lang3:Apache Commons项目的通用工具类库,提供了许多常用的工具方法,如字符串处理、日期处理、类型转换等。
  • spring-boot-starter-aop:Spring Boot的AOP(面向切面编程)框架,可以实现横切关注点的模块化编程。
  • aspectjrt:AspectJ的运行时库,支持在Java应用程序中使用AspectJ进行横切关注点的编程。
  • aspectjweaver:AspectJ的织入器库,用于在Java应用程序中实现AOP编程。
  • knife4j-spring-boot-starter:基于Swagger的API文档框架,提供了强大的接口文档生成和展示功能。
  • hutool-all:Java工具类库,提供了丰富的工具方法,包括字符串操作、日期时间处理、加密解密、文件操作等。
  • api-common:自定义的公共 API 模块。
  • dubbo-spring-boot-starter:基于 Spring Boot 的 Dubbo 框架依赖,用于构建和部署 Dubbo 应用。
  • dubbo-registry-nacos:Dubbo 的 Nacos 注册中心依赖,用于将 Dubbo 服务注册到 Nacos 中心,并实现服务的发现和路由。
<dependencies>
  
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
   
  	<dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <scope>runtime</scope>
    </dependency>
    
  	<dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    
  	<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    
  	<dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter-test</artifactId>
        <version>3.0.2</version>
        <scope>test</scope>
    </dependency>
    
  	<dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.12.0</version>
    </dependency>
    
  	<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    
  	<dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
    </dependency>
    
  	<dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
    </dependency>
    
  	<dependency>
        <groupId>com.github.xiaoymin</groupId>
        <artifactId>knife4j-spring-boot-starter</artifactId>
        <version>3.0.3</version>
    </dependency>

    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.8.9</version>
    </dependency>

    <dependency>
        <groupId>org.example</groupId>
        <artifactId>api-common</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>3.0.9</version>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-registry-nacos</artifactId>
        <version>3.0.9</version>
    </dependency>

</dependencies>
api-interface(Spring Boot 项目)
功能介绍

提供具体的接口服务

依赖管理
  • spring-boot-starter-web: 提供了构建基于 Spring Boot 的 Web 应用程序所需的依赖项,包括 Spring MVC,Tomcat 服务器和其他与 Web 开发相关的库。
  • lombok:通过注解来简化 Java 代码的编写,包括生成 getter 和 setter 方法、构造函数、equals 和hashCode 方法等,减少了冗余代码的编写,提高了代码的可读性和可维护性。
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

辅助项目设计

api-common(Maven 项目)
功能介绍
  • 共享代码:共享一份统一维护的公共代码
    • model:内部服务间 RPC 调用相关实体
    • service:内部服务间 RPC 调用相关接口
  • 共享依赖:共享一份统一维护的公共依赖
    • 为公共代码提供必要的注解
    • 为其他子项目提供公共依赖
依赖管理
  • org.mybatis.spring.boot:mybatis-spring-boot-starter:该依赖是用于集成MyBatis和Spring Boot的起步依赖。它简化了MyBatis和Spring Boot的配置,可以快速集成并使用MyBatis进行数据库操作。
  • com.baomidou:mybatis-plus-boot-starter:该依赖是MyBatis-Plus的Spring Boot启动器。MyBatis-Plus是在MyBatis基础上的增强工具,可以进一步简化数据库操作。它提供了更多的CRUD操作方法,以及一些常用的数据库操作功能,如分页查询、条件查询等。
  • org.projectlombok:lombok:该依赖是一个Java库,可以通过注解的方式简化Java类的编写。
  • com.google.code.gson:gson:该依赖是Google提供的Java库,用于处理JSON数据。它提供了一些方法,可以将Java对象转换为JSON字符串,或将JSON字符串转换为Java对象。在开发中,我们经常需要将Java对象和JSON数据进行转换,使用gson可以简化这个过程。
<dependencies>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.3.1</version>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.1</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.24</version>
    </dependency>
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.9.0</version>
    </dependency>
</dependencies>
api-client-sdk(Maven 项目)
功能介绍
  • 外部配置:作为一个 starter,支持 通过 application.yaml 实现外部配置 的机制 → 可以在 application.yaml 中配置 ak 和 sk

  • 模拟服务调用辅助

    • 提供 gateway 的 host

    • 为模拟请求添加额外的请求头

      • 访问密钥:源于 application.yaml 中的配置

      • 请求标识:实时生成 4 位随机数

      • 请求体:从请求中获取

      • 时间戳:实时生成时间戳

      • 签名:利用请求体和源于 application.yaml 中配置的 secretKey,生成签名

  • 签名服务:提供定位为 Utils 的工具方法,根据传输内容和 sk 生成签名,用于校验请求的完整性和一致性

依赖管理
  • spring-boot-configuration-processor:该依赖是 Spring Boot 的配置处理器,它可以在编译时生成和处理配置类,以提供更好的配置支持。
  • spring-boot-starter:该依赖是 Spring Boot 的核心启动器,它包含了 Spring Boot 应用所需的基本依赖,例如 Spring MVC、Spring Boot 自动配置、日志、Web 开发所需等。
  • hutool-all:该依赖是 Hutool 工具库的整合包。Hutool 是一个 Java 工具类库,提供了很多常用的工具方法和功能,例如字符串处理、日期时间处理、加密解密、文件操作、网络请求、JSON 解析等,方便开发者进行常见任务的处理和开发。
  • lombok:该依赖是 Lombok 库,它通过注解的方式简化了 Java 类的编写,并提供了一些常用的工具注解,如@Data@Getter@Setter@ToString等。使用 Lombok 可以减少代码的重复编写,提高开发效率。
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.8.9</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

关键业务流程

信息管理请求
graph LR api-frontend --1.crud请求--> api-gateway --2.crud请求--> api-backend --3.crud响应--> api-gateway --4.crud响应--> api-frontend
接口调用请求
graph LR api-frontend --1.接口调用请求--> api-gateway --2.接口调用请求--> api-interface --3.接口调用响应--> api-gateway --6.接口调用响应--> api-frontend api-gateway --4.调用信息更新请求--> api-backend --5.调用信息更新响应--> api-gateway

机制总结

自定义 spring-boot-starter 机制

spring-boot-starter 职责
  • 本质上是一个 Maven 项目,继承 Maven 职责

    • 为其他项目提供公共代码

      • model
      • service
    • 依赖管理

      • 为公共代码提供必要依赖
      • 为其他项目提供公共依赖
  • 作为 spring-boot-starter 的特有职责

    • 通过 application.yaml 实现外部配置
spring-boot-starter 实例
依赖管理
<dependencies>
  	<!--外部配置必备依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>
  	<!--业务功能相关依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.8.9</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>
业务功能
/**
 * 调用第三方接口的客户端
 *
 * 具体功能:
 * 1.记录用户公钥私钥
 * 2.增加请求头信息(待传输内容 + 用户身份验证信息 + 时间戳)
 * 3.提供网关地址
 *
 */
public class ApiClient {

    private static final String GATEWAY_HOST = "http://localhost:8090";

    private String accessKey;

    private String secretKey;

    //配置用户的公钥私钥,相当于账号密码
    public ApiClient(String accessKey, String secretKey) {
        this.accessKey = accessKey;
        this.secretKey = secretKey;
    }

    //增加请求头参数(访问密钥,请求标识,请求体,时间戳,生成的签名)
    public Map<String, String> getHeaderMap(String body) {
        Map<String, String> hashMap = new HashMap<>();
        // 访问密钥,即公钥
        hashMap.put("accessKey", accessKey);
        // 就算是密文传输也一定不能直接发送
        // hashMap.put("secretKey", secretKey);
        // Nonce 是 Number once 的缩写,用于标记请求
        // 在密码学中 Nonce 是一个只被使用一次的任意或非重复的随机数值
        hashMap.put("nonce", RandomUtil.randomNumbers(4));
        // 请求内容
        hashMap.put("body", body);
        // 时间戳
        hashMap.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
        // 签名
        hashMap.put("sign", genSign(body, secretKey));
        return hashMap;
    }

    public static String getEncodedGatewayHost() {
        return encode(GATEWAY_HOST);
    }

    public static String encode(String text) {
        byte[] encodedBytes = Base64.getEncoder().encode(text.getBytes());
        return new String(encodedBytes);
    }

    public static String decode(String text) {
        byte[] decodedBytes = Base64.getDecoder().decode(text);
        return new String(decodedBytes);
    }

}
/**
 * 签名工具
 *
 */
public class SignUtils {
    /**
     * 生成签名,确保数据在传输过程中没有被篡改或者被冒充
     * @param body
     * @param secretKey
     * @return
     */
    public static String genSign(String body, String secretKey) {
        // 创建 SHA256 的消息摘要器
        Digester md5 = new Digester(DigestAlgorithm.SHA256);
        // 将请求体和密钥拼接起来以生成待签名的内容
        String content = body + "." + secretKey;
        // 使用消息摘要器计算内容的哈希值,并以十六进制形式返回
        return md5.digestHex(content);
    }
}
项目本体
/**
 * Api 客户端配置
 *
 */
@Configuration
@ConfigurationProperties("api.client")
@Data
@ComponentScan
public class ApiClientConfig {

    private String accessKey;

    private String secretKey;

    @Bean
    public ApiClient yuApiClient() {
        return new ApiClient(accessKey, secretKey);
    }

}
stater 配置

套路固定,在 resource 文件夹下创建以下内容,文件结构、文件名称均不可修改

  • META-INF:文件夹

    • spring. factories:starter 配置文件

      # spring boot starter
      org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.sdk.ApiClientConfig
      
  • application.properties:项目配置文件,可以为空

ak-sk 机制

知识补充:ak-sk 机制
基础知识

ak-sk(Access key - Secret key)机制是一种常用的身份验证机制,用于保护云平台或 Web 服务的 API 调用安全。它基于加密算法,使用了公钥和私钥的概念。

  • Access key(访问密钥,即公钥)是用于标识和鉴别用户的唯一凭证,类似于 用户名。它由云平台或 Web 服务提供商分配给用户。
  • Secret key(私有密钥,即私钥)是与特定访问密钥关联的 密码,用于对 API 调用进行签名和加密。它由用户在访问密钥创建时自行设置。

在使用 Access key secret key 进行 API 调用时,通常需要将 Access key 和 Secret key 作为参数传递给 API 接口。服务提供商会使用 Secret key 对 API 请求进行签名,然后服务端使用对应的 Access key 和 Secret key 进行验证,并判断访问权限。

通过这种机制,可以实现用户身份验证和授权,确保只有具有正确 Access key 和 Secret key 的用户才能访问和调用服务,并确保数据在传输过程中的安全性。

在该机制中,Access Key 被视为公钥,用于标识用户的身份。Secret Key 则被视为私钥,用于加密签名,确保消息的完整性和安全性。

用户在使用服务时,需要提供 Access Key 和 Secret Key 进行身份验证,以获取访问权限。Access Key 用于标识用户的身份,Secret Key 则用于生成签名,确保请求的真实性和完整性。

这种机制可以有效地保护用户的账号安全,并控制用户对资源的访问权限。用户可以根据需要生成和管理多对 Access Key 和 Secret Key,以便于更灵活地管理和控制访问权限。

ak-sk 机制 vs 账号密码机制

AK-SK(Access Key & Secret Key)机制是一种身份验证机制,主要用于访问云服务的API接口。AK是用于标识用户身份的访问密钥,SK是用于对访问请求进行数字签名,确保请求的完整性和安全性。

而用户账号密码机制是指用户通过用户名和密码的方式进行身份验证。用户在注册云服务账号时会设置用户名和密码,在进行认证时需要提供正确的用户名和密码才能登录到账号。

AK-SK机制相比于用户账号密码机制更安全,因为AK-SK是由一对密钥组成,只需要将AK保密,而不需要传输密码,可以大大降低密码泄露的风险。而用户账号密码机制需要用户重复输入密码,容易受到密码被盗窃或猜测的风险。

另外,AK-SK机制可以进行权限控制,可以基于不同的AK设置不同的权限,实现细粒度的访问控制。而用户账号密码机制通常只有一个主密码,难以进行细粒度权限控制。

AK-SK机制 用户账号密码机制
身份验证方式 基于密钥 用户名和密码
密钥管理 用户自行管理 服务提供者管理
安全性 需要将密钥保密 需要保护好密码
密钥复用 可以在多个服务中复用 每个服务都有独立的账号密码
可撤销性 用户可以随时撤销并重新生成 用户可以修改密码
本项目中为什么要引入 ak-sk 机制?

接口调用时,有必要对调用者进行身份验证

最简单的验证方法就是通过用户的账号密码进行验证,但是这种验证的坏处就是 每次调用接口都要输入账号密码

这对于需要反复调用接口的接口平台而言操作太复杂了,有必要引入一套更简便的身份验证机制,该机制要求:

  1. 与用户账号(唯一)相关 → 方便建立用户验证机制和 ak-sk 验证机制的映射关系
  2. 与用户密码无关 → 与账号密码机制隔离,保证安全性
  3. 验证信息作为用户态信息的一部分 → 一次登录,反复调用 By 引入自动化验证
ak-sk 机制实现
ak-sk 分配

注册时分配

//注册时根据 userAccount 分配 accessKey, secretKey
//利用 SALT 和 随机数 提升加密强度
String accessKey = DigestUtil.md5Hex(SALT + userAccount + RandomUtil.randomNumbers(5));
String secretKey = DigestUtil.md5Hex(SALT + userAccount + RandomUtil.randomNumbers(8));
知识补充:彩虹表

彩虹表是一种用于破解密码的攻击方法之一。它是由一组预先计算好的明文密码和相应的哈希值组成的表格。通过对输入的密码进行哈希运算,可以在彩虹表中查找对应的哈希值,进而得到相应的明文密码。

彩虹表的原理是利用了哈希函数的确定性特性,即相同的输入会产生相同的输出。通过预先计算明文密码和对应的哈希值,可以大幅度提高破解密码的效率,特别是对于使用弱密码的情况。

为了缓解彩虹表对密码的破解威胁,可以采用以下方法之一:

  1. 使用不同的盐值:在密码的哈希计算过程中添加随机的盐值,使得彩虹表无法生成所有可能的密码和哈希值的对应关系。
  2. 使用更强的哈希函数:选择具有足够强度的哈希函数,使得彩虹表构建难度更大,破解密码的成本更高。
  3. 使用二次哈希:对哈希值再次进行哈希运算,增加破解密码的难度。

总之,彩虹表是一种密码破解的方法,使用盐值、强哈希函数和二次哈希等措施可以增强密码的安全性。

知识补充:盐值

盐值在加密中起到增加密码强度的作用。在加密过程中,将密码与随机生成的盐值进行组合,然后再进行哈希计算。盐值能够使得相同的密码在加密后生成不同的哈希值,增加了破解密码的难度。由于盐值是随机生成的且与密码相关联,破解者无法事先预知盐值,因此无法通过彩虹表等常见攻击手段破解密码。同时,盐值还可以对抗暴力破解和字典攻击,因为破解者需要尝试每个密码的不同盐值的哈希值,增加了破解的时间和资源成本。

ak-sk 机制使用

此处将 ak-sk 作为

  • 防止原始密码泄漏的安全机制
  • 免密接口调用权限验证机制

ak-sk 由用户注册时提供的用户名产生,并作为用户信息的一部分存储在用户信息表中

用户登录后,用户态中包含了 ak-sk 的信息,这使得用户在调用服务时无需额外输入密码,直接从用户态中获取 ak-sk,便可完成对于用户身份的验证,类比 令牌

解决方案总结

Spring Cloud Gateway 使用

依赖引入
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
    <version>3.1.3</version>
</dependency>
application 配置
spring:
  cloud:
    gateway:
      globalcors: # 跨域处理
        corsConfigurations:
          '[/**]':
            allowedOrigins:
              - "http://127.0.0.1:5500"
              - "http://localhost:8000"
            allowedMethods:
              - GET
              - POST
            allowedHeaders: "*"
            allowCredentials: true
      default-filters:
        - AddResponseHeader=source, api-gateway # 流量染色,说明响应源于 api-gateway
      routes:
        - id: backend_route # 请求转发到 api-backend
          uri: http://localhost:8080
          predicates:
            - Path=/api/backend/**
        - id: interface_route # 请求转发到 api-interface
          uri: http://localhost:8100
          predicates:
            - Path=/api/interface/**

Dubbo + Nacos 实现服务间 RPC 调用

参考文档

环境准备

安装并启动 Nacos

common
项目初始化

新建空的 Maven 项目

公共接口声明
public interface SayService {

    /**
     * 根据名字say hello
     * @param name 名字
     * @return name + ,hello!
     */
    String sayHelloByName(String name);
}
依赖安装
mvn install
provider
项目初始化

初始化为 Spring Boot 项目

Maven 依赖
  • Spring Boot 基础依赖
  • dubbo 基础依赖
  • dubbo 注册中心依赖:相当于 nacos-client
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>3.0.9</version>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-registry-nacos</artifactId>
        <version>3.0.9</version>
    </dependency>

    <dependency>
        <groupId>org.example</groupId>
        <artifactId>common</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>

</dependencies>
application.yml
server:
  port: 14511
spring:
  application:
    name: provider-service
  main:
    allow-bean-definition-overriding: true
dubbo:
  application:
    name: provider-service
  registry:
    address: nacos://127.0.0.1:8848
    username: nacos
    password: nacos
  scan:
    base-packages: com.example.provider.service.impl
  protocol:
    name: dubbo
    port: 15511
公共接口实现
@DubboService
public class SayServiceImpl implements SayService {

    @Override
    public String sayHelloByName(String name) {
        return name + ",hello!";
    }
}
启动类
@EnableDubbo
@SpringBootApplication
public class ProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class, args);
    }

}
consumer
项目初始化

初始化为 Spring Boot 项目

Maven 依赖
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
        <version>3.0.9</version>
    </dependency>

    <dependency>
        <groupId>org.apache.dubbo</groupId>
        <artifactId>dubbo-registry-nacos</artifactId>
        <version>3.0.9</version>
    </dependency>

    <dependency>
        <groupId>org.example</groupId>
        <artifactId>common</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>

</dependencies>
application.yml
server:
  port: 14510
spring:
  application:
    name: consumer-serivce
  main:
    allow-bean-definition-overriding: true
dubbo:
  application:
    name: consumer-serivce
  registry:
    address: nacos://127.0.0.1:8848
    username: nacos
    password: nacos
Controller
@RestController
@RequestMapping("/demo/say")
public class SayController {

    @DubboReference
    private SayService sayService;

    @GetMapping("/sayHello")
    public ResponseEntity<String> sayHello(@RequestParam("name") String name) {
        return ResponseEntity.ok(sayService.sayHelloByName(name));
    }
}
启动类
@EnableDubbo
@SpringBootApplication
public class ConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }

}
测试流程
  1. Provider 启动

  2. Consumer 启动

  3. 通过 Consumer 的 Controller 访问 Provider 的 Service

    curl "http://127.0.0.1:14510/demo/say/sayHello?name=test"
    

项目源码

https://github.com/Ba11ooner/api-project

posted @ 2023-09-03 10:58  Ba11ooner  阅读(2219)  评论(0编辑  收藏  举报