业界首创-六类请求对象把公网内网与鉴权写进类型系统

业界首创?六类请求对象把公网、内网与鉴权写进类型系统

架构判断: 请求对象不只是字段容器。它应该让方法签名直接暴露流量方向、登录要求和业务参数形态,让错误的接口声明在代码评审阶段就显形。

很多 Java 项目为每个接口创建一个 Request DTO,业务字段很清楚,信任边界却是隐形的:这是公网请求还是服务间调用?是否必须登录?签名、密文和用户身份应该在哪一层消失?

当这些答案藏在 URL、注解组合和开发者记忆里,接口越多,漏鉴权、重复解析 Token、外部字段穿透内部服务的概率就越高。问题不在 DTO 数量,而在类型没有表达架构事实。

MetaLite 把请求定义成一个正交类型系统:流量方向 × 登录要求 × 业务参数形态,最终收敛为六个请求类;业务参数再统一实现 Param,由泛型和校验注解建立硬约束。本文结合请求基类、Gateway/Admin 两侧 SysUserApiWebUtil 源码验证这套设计。

这里的“首创”是作者对完整组合的原创设计主张,不等同于已经穷尽全球代码库、论文或专利。真正值得讨论的不是标签,而是它能否用类型消灭一批本可避免的接口错误。

先把整套设计压缩成一张首屏判定表:

代码元素只负责表达什么形成的硬约束
External* / Internal*公网或内网信任边界评审时直接识别流量方向
ExternalLogin*是否要求登录登录要求不再藏在注解组合里
*BizParamReq<T extends Param>是否携带业务载荷Entity、DTO、Map 不能误入参数槽位
@NotNull + @Valid对象存在且字段合法缺少载荷与字段非法走统一校验入口

核心公式只有一句:方法名描述业务动作,请求外壳描述信任边界,Param 描述业务输入。 六个请求类不是为了穷举所有组合,而是主动删除“内网再次携带公网登录凭证”等非法状态。

一、一个接口签名,至少应该暴露四层事实

传统接口只暴露业务参数:

Resp<UserDto> create(@RequestBody SaveUserRequest request)

阅读者仍要去翻注解、过滤器和文档,才能确定安全规则。MetaLite 希望签名本身回答四个问题:

必须回答的问题由什么表达错选类型的直接风险
请求来自公网还是内网External* / Internal*公网协议穿透业务服务,或内网接口误暴露
是否要求登录ExternalLogin*漏校验 Token,或登录接口陷入“先登录才能登录”
是否携带业务参数*BizParamReq<T>空壳请求混入业务字段,校验入口不统一
业务参数是什么T extends Param使用裸 Map、Object 或任意 POJO,契约不可检索

这不是“多建几个类”,而是把接口评审从“相信开发者记得规则”变成“检查类型是否选对”。

二、三个维度为什么收敛成六种请求

InternalReq
  └── InternalBizParamReq<T extends Param>

ExternalReq
  ├── ExternalBizParamReq<T extends Param>
  └── ExternalLoginReq
        └── ExternalLoginBizParamReq<T extends Param>
请求类型边界代表性接口声明
ExternalReq公网、免登录、无参数Resp<SystemStatusDto> status(ExternalReq req)(标准模板)
ExternalBizParamReq<T>公网、免登录、有参数Resp<LoginDto> login(ExternalBizParamReq<LoginParam> req)
ExternalLoginReq公网、登录、无参数Resp<SysUserEntity> getMyself(ExternalLoginReq req)
ExternalLoginBizParamReq<T>公网、登录、有参数Resp<Void> createUser(ExternalLoginBizParamReq<SaveSysUserParam> req)
InternalReq内网、无参数Resp<SysUserEntity> getMyself(InternalReq req)
InternalBizParamReq<T>内网、有参数Resp<Void> createUser(InternalBizParamReq<SaveSysUserParam> req)

三个二元维度理论上能组成八种组合,MetaLite 却主动删掉了“内网再次携带登录凭证”的两种。用户身份应由 Gateway 建立,再通过受控 Header 与 ThreadContext 传播;内部服务不应每跳重新解析公网 Token。

少掉的两个类型,恰恰是设计价值。 类型系统不是枚举所有可能,而是删除架构上不应存在的状态。

三、Param 不是命名后缀,而是请求载荷的准入证

Param 本身很薄:

public interface Pojo extends Serializable {}

public interface Param extends Pojo {}

薄不等于没有约束。首屏表格中的三道门分别在编译期、对象校验期和字段校验期生效。例如 SaveSysUserParam implements Param,用户名和手机号使用 @NotBlank;类型先证明它属于业务入参,@NotNull 再证明载荷存在,@Valid 最后递归验证字段。

需要把边界说清:Param 目前是标记接口,不会自动禁止业务逻辑、可变字段或 Entity 继承;这些仍需要包结构规范和 ArchUnit 等静态规则继续收紧。但它已经让所有带参请求拥有统一、可搜索、可扩展的准入点。

ExternalReq 一行是框架支持模板外,其余类型均对应当前 Gateway/Admin 的真实接口形态。

四、同一个业务接口,公网与内网只改变外壳

以登录为例,Gateway 接收公网类型:

@PostMapping("/login")
public Resp<LoginDto> login(
        @RequestBody @Valid ExternalBizParamReq<LoginParam> req,
        BindingResult bindingResult) {
    return internalServiceClient.callOneInstanceRtnData(
            RpcRequest.builder()
                    .param(WebUtil.genInternalReq(req, LoginParam.class))
                    .build(),
            LoginDto.class);
}

Admin 的同路径接口只接收内部类型:

@PostMapping("/login")
public Resp<LoginDto> login(
        @RequestBody @Valid InternalBizParamReq<LoginParam> req,
        BindingResult bindingResult) {
    return sysUserService.login(req.getBizParam());
}

LoginParam 没变,业务语义没变,改变的是信任外壳。Gateway 负责调用方、时间、签名、加密和用户协议;Admin 只消费已经收敛后的业务参数。

五、公网系统字段为什么不能塞进 Param

ExternalReq 统一承载公网协议字段:

字段责任不属于业务 Param 的原因
apiVersion外部协议版本协议演进不应修改每个业务类
appId调用方身份属于 Gateway 安全域
timestamp时间窗与防重放输入不是业务发生时间
sign系统参数签名签名算法由调用方配置决定
plaintext明文业务 JSON是外部传输形态,不是 Service 入参
encryptData加密业务 JSON不应进入内部业务模型

ExternalLoginReq 只追加 userToken。而外部 *BizParamReq<T> 中的 bizParam 主要用于 OpenAPI Schema 展示,源码已注明调用方不要直接上送;真实载荷走 plaintextencryptData,由 Gateway 解密后按 Param 类型恢复。

六、类型如何驱动处理器,而不是只服务命名

类型命中框架职责
ExternalReq调用方、时间、IP、签名等校验
ExternalLoginReqToken 校验与用户上下文建立
外部请求含业务载荷解密并生成指定 Param
内部 RPC 发起填充 provider、consumer 与上下文 Header
外部响应要求加密data 加密为 encryptData,再清空明文

CallerAuthHandler 查找 ExternalReqUserAuthHandler 查找 ExternalLoginReq。因此 ExternalLoginBizParamReq 会自然继承调用方认证与用户认证,而不是在 Controller 上重复声明两组开关。

WebUtil.genInternalReq 则完成信任收敛:外部无参请求变成 InternalReq;外部有参请求读取 plaintext、校验 JSON 对象形态、按指定 Param 类型反序列化,再生成 InternalBizParamReq<T>

七、首创式设计最需要公开的边界

  • InternalReq 是协议类型,不是服务身份证书;内部端口仍需要网络隔离或服务间认证。
  • 当前类型没有表达 HTTP Method、幂等性、租户和数据权限,不能让请求基类承担所有治理职责。
  • ExternalReq 的无业务参数标准场景已有实现能力,但当前没有直接业务 Controller 实例,不能把模板写成既成案例。
  • Param 是准入标识而非不可变对象约束,仍需静态架构测试防止 Entity、DTO 和 Param 相互污染。
  • 如果内部接口允许绕过 Gateway 并伪造身份 Header,类型系统无法独自建立可信身份。

八、发布前只需要破坏这七条不变量

破坏场景必须断言
公网 appId、时间戳或签名无效目标方法执行前拒绝
登录接口使用无登录类型代码评审或架构测试阻断
userToken 无效不建立 loginUserId
plaintext 不是对象 JSON不生成内部 Param
Param 为空或字段非法@NotNull/@Valid 阻断 Service
provider/consumer 缺失RPC 发出前失败
绕过 Gateway 伪造身份 Header网络或服务认证层拒绝

六个请求类最有价值的地方,不是数量恰好为六,而是让错误选择留下明确证据。MetaLite 的接口哲学可以压缩成一句话:安全策略不要只写在文档里,要尽可能写进类型、继承关系、泛型上界和处理器选择规则。


框架简介
MetaLite 是面向企业生产环境的新一代 Java 微服务技术底座。系列文章重点分享代码背后的设计思路、技术取舍与工程实践。

源码基线
JDK 21、Spring Boot 3.2.9、Spring Cloud 2023.0.1、Spring Cloud Alibaba 2023.0.1.3,具体组件版本以项目 backend-bom 为准。

作者简介
15 年 Spring 体系企业级开发经验,专注于 Java 微服务架构、工程治理与生产实践。

持续更新
MetaLite 系列内容将持续更新,围绕核心设计、源码链路、技术取舍与生产实践展开。欢迎关注作者,及时获取后续内容。

在线演示
演示地址: https://admin.metalite.top/
演示账号: guess
演示密码: admin@2026

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值