WX20221008-141040@2x.png

Naive BFF

在《https://zhuanlan.zhihu.com/p/442433967》一文里,以 BFF 为中心,简要地回顾了一下自己做的项目。从 2018 年开始,就一直和 BFF 打交道,但是看来一直在 Naive BFF 的级别上折腾。

Naive BFF 是我杜撰的词,意味着只做后端服务的聚合与裁剪的“转发式” BFF。但即使是这种 Naive BFF,也还没有做到很纯粹,即仍然有 BFF 缺失的场景,如下图所示:
image.png

TMI BFF

BFF 是为前端专做的后端,理论上前端要使用的所有能力都应该由 BFF 来转发,当然也包括用户认证与授权部分。然而,可能由于 OAuth 2.0 的流行,以及其提供的隐式授权授权模型以及对公开客户端的支持,特别方便于前端直接和授权服务器交流,所以导致前端直接对接了授权服务(未经 BFF 中转请求)。在《https://zhuanlan.zhihu.com/p/533197284》一文中,以一个 antd 前端为例,详解了如何对接 IdentityServer,从而保护需要用户信息的路由(页面)。在这个例子中,就是使用了纯前端的插件 umi-plugin-oauth2,来直接和 IdentityServer 来交流,以获取用户 token、身份信息等等。

这样虽然完全可以工作,但毕竟非常不安全,所以有一个 BFF 标准正在被提出,即 TMI BFF。详细文档见: https://datatracker.ietf.org/doc/html/draft-bertocci-oauth2-tmi-bff-00。这个标准用 BFF 将前端和授权服务器隔开,代为获取令牌。但是仍然要求前端自行保存令牌,并且后续直接和资源服务直接交流。

image.png

Full BFF

完整的 BFF 应该将对资源服务的请求也接管过来,前端接触不到令牌,也不会保存在客户端的任何地方。其实,这才回归了 BFF 架构的初心,即一个前端,一个后端。再后面的服务,对前端是透明的,由这个 BFF 后端统一承接。

WX20221008-154538.png

那么,前端没有任何令牌信息的情况下,如何实现登录状态呢?其实仍然是 Cookie,即回归到了 Token + Session 的管理模式,而不再是单一 Token 模式。单一 Token 模式容易千万覆水难收的情况,比如 Keycloak 的单一退出接口,就没有很方便的办法让已颁发的 Token 失效。详细讨论见: https://www.zhihu.com/consult/conversation/1557672350673453056/archive?showIWantConsult=1&showFixedBtn=1

不过,这个 Cookie 是 HttpOnly + Secure + SameSite Strict,从而规避了从客户端窃取登录信息的风险。

WX20221008-134513@2x.png

Full BFF 应该有如上图的组成部分,当然它不限制开发语言,但上图带上了 ASP.NET Core,是因为主讲者是 Duende IdentityServer 的联合创始人,而 IdentityServer 是一个基于 ASP.NET Core 的认证授权中间件。

之前写过《https://zhuanlan.zhihu.com/p/486268896》讨论 IdentityServer 的卖点,其中之一是它宣称高安全性,看来此言不虚。它为 Full BFF 提供了很好的脚手架,看到 Full BFF 的组成部分不用担心,除了具体的 Endpoints,其他的不用从 0 开发。

总结

用一张图总结吧:
WX20221008-141040@2x.png