这是谁干的? 跨边界的身份

2026年8月9日1 次浏览来源:Dev.to阅读原文

你在认证方面做了很多工作 一个网关验证Keycloak JWT,将域名角色映射给当局,检查是否允许打电话者.

当一个请求到达你的服务, 你确切知道是谁在打电话。

然后,请求穿过 进入同源地, 所有的蒸发。

这个故事讲述了身份在事件驱动的系统中悄悄地消失,为什么死字队列是它消失的最糟糕的地方,以及我如何让演技用户像事件本身一样持久和重放安全.

大家相信的流水都不错 该平台是一集"春靴"服务:前方的API网关,MySQL上的一个,PostgreSQL上的一个,以及卡夫卡在它们之间进行活动.

创建用户,发布事件,发送通知.

认证在边缘处理.

网关是一个OAuth2资源服务器;它验证了符号一次,并在下游将呼叫者的身份传播为信头: 这里有一个细节比看起来更重要 信头总是被覆盖,即使没有权利要求。

如果客户端试图在输入请求上注入,网关会用被验证的值(或为空)来踩.

下游对这些信条的信任是安全的,因为周边的保证不能伪造.

错过了,你已经造了一个假冒的API。

目前还不错 同步跳动带有身份.

问题从一行开始 隐藏的失败:我不向卡夫卡发布请求中的线条边界.

我使用交易排出箱模式:请求将用户和排出箱持续在一个本地交易中,一个单独的预定的传票人发布到卡夫卡之后. (为什么:在请求中直接发布可以使DB行承担,然后在经纪人呼叫失败时丢失事件——双写问题.

收发箱关闭了那个缺口。 ) 脱钩是正确 交付。

这正是身份死亡的地方。

发箱出版商运行在预定的线程上,而不是请求线程上. ————你可能藏了"谁在打电话"的每一个环境地点——在传票人跑来的时候都空了.

没有人提出要求。

没有标志。

无所可读.

所以这个活动是匿名的 消费日志匿名.

通知是匿名的。

当一个事件耗尽了它的重复和在死字排队的地盘时——你迫切想知道是谁触发了它——死字行也是匿名的.

证据消失的正值 法医开始。

天真修正(以及为什么每个都失败) 诱人的答案都在同一边界上失败了:"只需在控制器中记录用户名".

你可以——但你所关心的日志行是发布,它后来在HTTP响应已经返回后在另一个线条上发生.

控制器日志告诉你一个请求到达了;它不能将20秒后失败的事件归为属性. "把它装入MDC / a Thread Local 在出版商中读取".

出版商没有在你的线上。

MDC是线程范围;预定的传票人从干净,空上下文开始.

你每次都会看的 更糟糕的是,在有集合载体的"虚拟线索"(Virtual Threads with couple carriers)下,一个 stale Thread Local是一个正确的危险——你可以将一个请求的身份泄露到另一个事件上. "出版社重读JWT".

没有范围要求,也没有重新生效的迹象。

认证事件早已结束.

每件天真的事 都假设身份处于环境线状状态 穿过一个星系边界,环境状态正是你没有的。

制作实施情况:持续认同活动 如果发布在时间和线程上与请求脱钩,那么身份必须像事件一样行走——数据而不是环境背景.

所以我在请求线条上捕捉到演员,并把它粘入出柜行,在与实体书写的同一交易中: 现在身份和事件一样持久 它在坠机、重启、重新部署中存活下来 因为它是一行人,

分享