Go 项目使用 Zitadel 作为身份认证中心

前言⌗
对于团队中存在多个项目需要开发的,且每个项目都需要实现用户认证和授权的团队来说,Zitadel 是一个比较好的解决方案,你无需为每个项目重新开发一天用户的认证和授权逻辑。
因为 Zitadel 支持多租户,且支持认证页面的品牌化定制。而作为后端,我们只需要接入官方的 SDK 即可!
如果不了解 Zitadel 的可以去看我的这篇文章 开源身份认证和授权解决方案。
概念⌗
Zitadel 为登录用户签发的 Token 有两种:
- Access Token
- ID Token
Access Token 又分为 Bearer Token 和 JSON Web Token,二者的区别就是是否携带一些基础数据。
ID Token 本质上也是 JWT 的一种,只是其中包含的用户信息更加全面,如包含用户的 Metadata,Role、Permission 等数据。
Token 的验证⌗
无论是 Access Token 还是 ID Token,要实现用户身份的确认,就必须验证请求中携带的 Token 是否是指定的 Issuer 签发的,并且是否被被篡改。
要实现这些,需要通过 RSA Public Key 来进行验签,这部分逻辑有专门的名词叫 Introspection,这里也有两种形式进行 Token 的验签:
- 资源服务器请求身份认证服务器的 Introspection Endpoint
- 资源服务器缓存身份认证服务器的 JWK Set(也就是 RSA 的 Public Key),在本地进行验证,这种方式被称为:Self-Introspection
但是这两种方式存在对应的优势和弊端,需要根据具体业务需求来决定所使用的方式。
通过 Introspection Endpoint 实现 Token 验证的这种方式,可以实现高度统一。当用户退出登录时,或者撤销令牌时,资源服务器可以从身份认证服务器的响应中得知令牌已经失效。但这种方式的问题也比较突出,就是每个请求需要去 Introspection Endpoint 验证,这样导致 API 响应的时间可能会增加几十到上百毫秒不等!
而 Self-Introspection 的这种方式,就是避免性能问题,通过缓存身份认证服务的 JWK Set,然后再本地对 Token 进行验证,这样减少了不必要的请求,对于响应的时间没有什么影响。但问题也比较的突出,那就是这个 Token 在有效期内无法被撤销!
所以,如果你的业务如果优先考虑安全性的话,那么选择通过 Introspection Endpoint 来进行验证,如果优先考虑性能的话,则选择 Self-Introspection!
项目集成⌗
- Zitadel 中创建项目,并为项目创建 Web 和 API 两个应用:
- Web 应用设置如下:
- API 应用下创建 Key
创建完成后,会提示下载一个 Key 的 JSON 文件,这个文件就是 middleware.OSKeyPath()
指向的文件,可以通过 ZITADEL_KEY_PATH
环境变量来设置这个 Key 的路径。
另外我所使用的框架是 fiber,基于 fastrouter 路由与 Go 自带的 些许不同!
Introspection⌗
代码说明:
- 20 行:声明拦截器
- 25 行:将中间件转为 fiber 的 Handler
目前官方的 SDK 尚未支持获取用户的信息,对与应用层来说只能知道 Token 是否有效,虽然在
/oauth/v2/introspect
的响应中,有用户的信息,但是在 SDK 中并未处理!
Self-Introspection⌗
代码说明:
- 19 行:声明 Remote Key Set,注意这个变量是全局是有状态的,用于缓存 Key Set
- 20 行:声明 Token 验证器
- 28 行:验证 Token 是否有效,并获取 Claims
- 34 行:将 Claims 放入 fiber.Ctx 中,便于后续逻辑中获取用户信息
总结⌗
到此,在 Go 项目中集成 Zitadel 就算完成了,对于小项目而言,采用这种方式,可以进一步降低开发周期,提前交付项目!
如果再进一步则可以在 API Gateway 或其他代理服务器,如 Traefik 上来实现用户认证和鉴权,后端通过约定好的请求头获取用户信息即可!
I hope this is helpful, Happy hacking…