你在认证方面做了很多工作 一个网关验证Keycloak JWT,将域名角色映射给当局,检查是否允许打电话者.
当一个请求到达你的服务, 你确切知道是谁在打电话。
然后,请求穿过 进入同源地, 所有的蒸发。
这个故事讲述了身份在事件驱动的系统中悄悄地消失,为什么死字队列是它消失的最糟糕的地方,以及我如何让演技用户像事件本身一样持久和重放安全.
大家相信的流水都不错 该平台是一集"春靴"服务:前方的API网关,MySQL上的一个,PostgreSQL上的一个,以及卡夫卡在它们之间进行活动.
创建用户,发布事件,发送通知.
认证在边缘处理.
网关是一个OAuth2资源服务器;它验证了符号一次,并在下游将呼叫者的身份传播为信头: 这里有一个细节比看起来更重要 信头总是被覆盖,即使没有权利要求。
如果客户端试图在输入请求上注入,网关会用被验证的值(或为空)来踩.
下游对这些信条的信任是安全的,因为周边的保证不能伪造.
错过了,你已经造了一个假冒的API。
目前还不错 同步跳动带有身份.
问题从一行开始 隐藏的失败:我不向卡夫卡发布请求中的线条边界.
我使用交易排出箱模式:请求将用户和排出箱持续在一个本地交易中,一个单独的预定的传票人发布到卡夫卡之后. (为什么:在请求中直接发布可以使DB行承担,然后在经纪人呼叫失败时丢失事件——双写问题.
收发箱关闭了那个缺口。 ) 脱钩是正确 交付。
这正是身份死亡的地方。
发箱出版商运行在预定的线程上,而不是请求线程上. ————你可能藏了"谁在打电话"的每一个环境地点——在传票人跑来的时候都空了.
没有人提出要求。
没有标志。
无所可读.
所以这个活动是匿名的 消费日志匿名.
通知是匿名的。
当一个事件耗尽了它的重复和在死字排队的地盘时——你迫切想知道是谁触发了它——死字行也是匿名的.
证据消失的正值 法医开始。
天真修正(以及为什么每个都失败) 诱人的答案都在同一边界上失败了:"只需在控制器中记录用户名".
你可以——但你所关心的日志行是发布,它后来在HTTP响应已经返回后在另一个线条上发生.
控制器日志告诉你一个请求到达了;它不能将20秒后失败的事件归为属性. "把它装入MDC / a Thread Local 在出版商中读取".
出版商没有在你的线上。
MDC是线程范围;预定的传票人从干净,空上下文开始.
你每次都会看的 更糟糕的是,在有集合载体的"虚拟线索"(Virtual Threads with couple carriers)下,一个 stale Thread Local是一个正确的危险——你可以将一个请求的身份泄露到另一个事件上. "出版社重读JWT".
没有范围要求,也没有重新生效的迹象。
认证事件早已结束.
每件天真的事 都假设身份处于环境线状状态 穿过一个星系边界,环境状态正是你没有的。
制作实施情况:持续认同活动 如果发布在时间和线程上与请求脱钩,那么身份必须像事件一样行走——数据而不是环境背景.
所以我在请求线条上捕捉到演员,并把它粘入出柜行,在与实体书写的同一交易中: 现在身份和事件一样持久 它在坠机、重启、重新部署中存活下来 因为它是一行人,