ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Fizzy Identity API 实战指南:身份账户查询与时区更新

Fizzy Identity API 实战指南:身份账户查询与时区更新 Fizzy Identity API 实战指南身份账户查询与时区更新【免费下载链接】fizzyKanban as it should be. Not as it has been.项目地址: https://gitcode.com/GitHub_Trending/fizzy2/fizzy导读Fizzy 是一个多租户看板Kanban应用而Identity身份是它账号体系的基石——它代表的不是某个工作区里的成员而是使用 Fizzy 的某个人可以横跨多个账户Account存在。本文围绕官方 API 文档中 Identity 的两个核心端点展开用GET /my/identity一次获取当前身份可访问的全部账户及其用户信息用PATCH /:account_slug/my/timezone调整当前用户的时区偏好。读完本文你将能够在自己的应用或脚本中完成启动时枚举账户这一典型集成动作并理解时区设置从 API 请求到通知邮件渲染的完整链路。文中所有接口细节均以官方文档为主干并结合 Fizzy 仓库源码模型、控制器、jbuilder 视图与路由进行深度印证。一、什么是 Identity跨越账户的人在深入接口之前先建立一个准确的概念模型。官方文档对 Identity 的定义非常简洁An Identity represents a person using Fizzy.在 Fizzy 的多租户设计中人是全局的账户是局部的。一个 Identity 可以加入多个账户在每个账户中对应一条独立的 User 记录。源码 app/models/identity.rb 印证了这一关系class Identity ApplicationRecord include Joinable, Transferable has_many :users, dependent: :nullify has_many :accounts, through: :users end其中Joinableapp/models/identity/joinable.rb提供了把身份加入账户的核心方法def join(account, **attributes) attributes[:name] || email_address transaction do account.users.find_or_create_by!(identity: self) do |user| user.assign_attributes(attributes) end.previously_new_record? end end一个值得注意的细节每个账户下的 User 记录默认以email_address作为名字——这正好解释了本文后面时区端点中 current user 的语义时区是按账户内用户User存储的而身份Identity本身不持有时区。多租户上下文通过 app/models/current.rb 贯穿整个请求周期Current.session→Current.identity→Current.user按当前账户从 identity 的 users 中解析构成了一次登录、多账户切换的基础。二、GET /my/identity获取身份与账户清单2.1 端点概览GET /my/identity该端点不需要账户上下文即不需要先访问某个/account_slug/...路径返回当前登录身份可访问的所有账户以及每个账户对应的用户信息。路由定义位于 config/routes.rb 的namespace :my块中namespace :my do resource :identity, only: :show resource :timezone # ... end控制器 app/controllers/my/identities_controller.rb 极其精简但有一处关键声明class My::IdentitiesController ApplicationController disallow_account_scope def show identity Current.identity end enddisallow_account_scope定义于 app/controllers/concerns/authentication.rb会跳过require_account前置钩子并拦截带账户上下文的请求从而保证该端点只依赖登录身份本身与当前处于哪个账户无关。2.2 身份认证方式该端点既支持个人访问令牌Personal Access Token也支持会话 Cookie# 方式一Bearer 令牌 curl -H Authorization: Bearer put-your-access-token-here \ -H Accept: application/json \ https://app.fizzy.do/my/identity # 方式二会话 Cookiemagic link 登录后 curl -H Cookie: session_tokeneyJfcmFpbHMi... \ -H Accept: application/json \ https://app.fizzy.do/my/identityBearer 令牌的校验逻辑在 app/controllers/concerns/authentication.rb 的authenticate_by_bearer_token中仅对 JSON 请求生效并通过Identity.find_by_permissable_access_token(token, method: request.method)app/models/identity.rb按 HTTP 方法校验令牌的读写权限。更完整的令牌申请、列举与删除流程见 docs/api/sections/authentication.md。2.3 响应结构逐字段解读官方文档给出的响应示例{ accounts: [ { id: 03f5v9zjskhcii2r45ih3u1rq, name: 37signals, slug: /897362094, created_at: 2025-12-05T19:36:35.377Z, user: { id: 03f5v9zjw7pz8717a4no1h8a7, name: David Heinemeier Hansson, role: owner, active: true, email_address: davidexample.com, created_at: 2025-12-05T19:36:35.401Z, url: http://app.fizzy.localhost:3006/users/03f5v9zjw7pz8717a4no1h8a7 } } ] }这个 JSON 并非手写示例而是由 jbuilder 模板逐字段渲染出来的源码清晰可查。外层响应由 app/views/my/identities/show.json.jbuilder 生成json.id identity.id json.accounts identity.users_with_active_accounts do |user| json.partial! my/identities/account, account: user.account json.user user, partial: users/user, as: :user end两个值得注意的实现细节只返回活跃账户users_with_active_accountsapp/models/identity.rb通过users.joins(:account).merge(Account.active)过滤已关闭deactivated的账户不会出现在列表中。响应带顶层id文档示例省略了顶层id即 Identity 自身的 ULID但实际渲染会输出json.id identity.id。账户片段由 app/views/my/identities/_account.json.jbuilder 渲染json.cache! account do json.(account, :id, :name, :slug) json.created_at account.created_at.utc end用户片段由 app/views/users/_user.json.jbuilder 渲染json.cache! user do json.(user, :id, :name, :role, :active) json.email_address user.identity.email_address json.created_at user.created_at.utc json.url user_url(user) json.avatar_url user_avatar_url(user) end各字段含义与数据来源汇总如下字段类型含义来源idstring账户/用户/身份的 ULID 主键模型主键namestring账户名 / 用户名Account / Userslugstring账户标识形如/897362094用于构造账户级 API 路径Accountcreated_atdatetime创建时间UTC模型时间戳rolestring用户在账户内的角色owner/admin/member/systemapp/models/user/role.rb 枚举activeboolean用户是否处于激活状态User#activeemail_addressstring身份邮箱跨账户共享user.identity.email_addressurlstring用户页面对外 URLuser_url(user)avatar_urlstring用户头像 URL响应中实际存在文档示例未列出user_avatar_url(user)角色枚举定义在 app/models/user/role.rbenum :role, %i[ owner admin member system ].index_by(:itself), scopes: false同时提供admin?super || owner?等权限判断owner是账户内的最高角色本文开头示例中 DHH 在 37signals 账户中的角色正是owner。2.4 典型使用场景该端点是客户端集成的入口端点最常见的用途是应用/脚本启动时枚举用户可用的全部账户随后再针对具体账户发起业务请求如/1234567/boards、/1234567/cards。配合slug字段如/897362094即可拼出账户作用域路径。由于响应中account片段启用了json.cache!并且控制器层通过etag { Current.identity.id }提供 ETagapp/controllers/concerns/authentication.rb客户端可配合If-None-Match做增量缓存账户列表未变化时直接命中304 Not Modified大幅减少重复拉取开销ETag 用法详见 docs/api/README.md。三、PATCH /:account_slug/my/timezone更新当前用户时区3.1 端点概览PATCH /:account_slug/my/timezone该端点更新当前账户上下文内当前用户的时区。官方文档明确说明其作用范围影响通知邮件notification emails中时间的显示方式。参数定义如下完全继承自官方文档参数类型必填说明timezone_namestring是IANA 时区标识符如America/New_York、Europe/London、Asia/Tokyo请求示例{ timezone_name: America/New_York }成功时返回204 No Content。3.2 源码实现链路控制器 app/controllers/my/timezones_controller.rb 是整条链路的入口class My::TimezonesController ApplicationController def update Current.user.settings.update!(timezone_name: timezone_param) head :no_content end private def timezone_param params[:timezone_name] end end可以看到时区并非存储在 Identity 上而是落在账户内用户User的 Settings 记录上。User通过Configurable模块app/models/user/configurable.rb维护这份设置has_one :settings, class_name: User::Settings, dependent: :destroy after_create :create_settings, unless: :system? delegate :timezone, to: :settings, allow_nil: true def time_zone(block) Time.use_zone(timezone, block) end也就是说每个用户创建时会自动生成一份User::Settings而timezone是这份设置的动态计算结果。3.3 时区解析与默认值设置的实际存储与解析逻辑位于 app/models/user/settings.rbdef timezone if timezone_name.present? ActiveSupport::TimeZone[timezone_name] || default_timezone else default_timezone end end def default_timezone ActiveSupport::TimeZone[UTC] end两个关键行为IANA 标识符解析timezone_name存的是America/New_York这类 IANA 名称通过ActiveSupport::TimeZone[...]解析为 Ruby 的时区对象TimeZone内部即映射 IANA 名称。容错回退若传入的名称无法解析拼写错误或不存在不会抛异常而是回退到默认时区UTC。未设置时同样默认 UTC。3.4 时区如何影响通知邮件timezone_name的语义在上游被Time.use_zone消费凡是需要在当前用户时区下渲染时间的代码都会通过user.time_zone { ... }包裹执行见 app/models/user/configurable.rb。官方文档所述的影响通知邮件中的时间显示正是通过这条委托链实现的——邮件模板在渲染时间戳时进入用户时区从而显示为当地时间而非服务器 UTC 时间。需要注意的是该设置按账户内用户生效同一个 Identity 在不同账户下有各自的 User 与 Settings因此时区偏好天然隔离不会跨账户串扰。3.5 路由与作用域路由同样定义在namespace :my中config/routes.rbresource :timezoneresource单数形式意味着这是一条单例资源路由——用户没有多个时区只有一个偏好设置。完整路径为PATCH /:account_slug/my/timezone其中:account_slug是账户级作用域前缀如/897362094与GET /my/identity这类全局端点在作用域上形成互补一个是账户无关的全局视图一个是账户内的用户偏好。四、实践建议与注意事项启动流程推荐组合先GET /my/identity拿到账户清单含 slug再逐账户调用业务 APIIdentity 顶层id可用于客户端本地关联身份缓存。时区名称必须使用 IANA 标识符不要传EST、GMT8这类缩写或偏移量ActiveSupport::TimeZone按 IANA 名称解析非法值会静默回退为 UTC——排查时区没生效时优先检查拼写。区分全局端点与账户端点GET /my/identity无账户前缀且禁用了账户作用域disallow_account_scope而时区端点必须携带:account_slug二者不可混用。响应缓存GET /my/identity的账户片段启用了片段缓存且响应带 ETag高频轮询应使用If-None-Match以节省带宽。权限提示该端点的语义对象是当前用户即认证身份在当前账户下的 User 记录如果请求未携带有效账户上下文会因require_account失败而无法命中因此调用前请确认已先进入目标账户作用域如通过/1234567前缀的请求建立账户上下文。五、小结Identity 是 Fizzy 多租户账号体系的核心抽象一个人Identity跨多个账户Account每个账户内体现为一条 User 记录。GET /my/identity是这个体系面向 API 的窗口——一次请求即可枚举身份的全部活跃账户及其用户信息适合作为集成客户端的启动入口PATCH /:account_slug/my/timezone则把 IANA 时区偏好写入账户内用户的 Settings经ActiveSupport::TimeZone解析、Time.use_zone消费最终体现在通知邮件的本地化时间渲染上。两个端点一全局一账户内共同构成了 Fizzy 身份层对外部应用最基本的两个操作。想要进一步探索身份机制推荐继续阅读 app/models/identity.rb、app/models/current.rb 与 docs/api/sections/authentication.md。【免费下载链接】fizzyKanban as it should be. Not as it has been.项目地址: https://gitcode.com/GitHub_Trending/fizzy2/fizzy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表