)
后端工作流自动化流程编排低代码【免费下载链接】elsa-coreThe Workflow Engine for .NET项目地址https://gitcode.com/gh_mirrors/el/elsa-core点击查看免费下载导读本文围绕 Elsa 工作流引擎elsa-core外部认证模块Elsa.ExternalAuthentication的一项核心架构决策展开如何用一个不可变的逻辑 Connection Key 标识宿主机级host-wide的身份提供方连接并让配置基线configuration baseline与 Studio 持久化覆盖persisted override在同一个生效注册表中共存且不互相污染。读完本文你将掌握逻辑键与数据库行 ID 的分工、显式覆盖的完整替换语义、遮蔽shadow关系的判定规则以及配置层与数据库层连接源的源码级组合原理可直接用于 Elsa 外部认证的部署与二次排障。该决策正式记录于架构决策文档 doc/adr/0021-identify-host-connections-by-logical-key-and-use-explicit-overrides.md并部分取代了此前关于作用域与来源优先级的 doc/adr/0015-compose-a-scoped-connection-registry.md。本文以该 ADR 为骨架结合src/modules/Elsa.ExternalAuthentication的源码实现逐一印证。一、决策背景为什么需要逻辑键 显式覆盖Elsa 外部认证 v1External Authentication v1把Identity Provider 连接Connection统一托管在当前所连接的 Elsa 服务器环境这个宿主范围内。这个环境属于运行时上下文而不是连接记录上一个可被持久化编辑的字段。每个连接同时存在两类身份信息管理/瞬态标识连接在数据库或配置记录中的 ID用于后台管理与 Broker 流程中的瞬态状态逻辑 Connection Key一个不可变的逻辑键用于跨配置来源、跨归档/恢复、跨持久化覆盖保持身份连续。关键设计约束来自 doc/adr/0015-compose-a-scoped-connection-registry.mdElsa 暴露一个由只读部署配置 可选的管理员持久化组合而成的连接注册表配置在冲突时拥有权威性被遮蔽的数据库记录以冲突形式可见每个租户的生效注册表中键唯一宿主级连接使用租户无关的*标识而空标识仍然是默认租户。在 ADR 0021 之前作用域与来源优先级已经由 0015 确立0021 进一步明确了连接的识别方式逻辑键与覆盖的替换语义完整替换、不做任何字段合并并宣布宿主级范围是 v1 的正式决策。二、核心概念不可变的逻辑 Connection Key2.1 逻辑键与数据库行 ID 的分工ADR 0021 的核心主张是不要用数据库行 ID 作为公开的认证标识。行 ID 属于存储实现细节会随记录迁移、归档/恢复、覆盖重建而变化而逻辑键是业务层面的稳定身份必须在以下生命周期事件中保持不变配置来源发生变化例如appsettings.json中该连接的字段被调整连接被归档archive后再恢复restore数据库记录被提升为覆盖配置的连接persisted override。这一分工在数据模型中有直接体现。IdentityProviderConnection 同时承载Id与Key两个字段Id用于存储与瞬态管理Key才是跨来源稳定的逻辑身份。Broker 的BrokerTransaction也同时保留两者——ConnectionId是in-flight 记录 ID而ConnectionKey是逻辑回调键与瞬态记录 ID 一起保留见 ExternalAuthenticationModels.cs。2.2 逻辑键在哪里被使用逻辑键是长期有效状态的唯一连接引用维度External Identity Link外部身份链接的元组是(targetTenantId, connectionKey, issuer, subject)见ExternalIdentityLink记录定义ExternalAuthenticationModels.cs与IExternalIdentityProvisioner.FindLinkAsync(tenantId, connectionKey, identity, ...)ExternalAuthenticationContracts.cs长期会话session保存在会话目标租户中解析后的规范化逻辑连接键ConnectionKey与ConnectionMaterialRevisionExternalAuthenticationModels.cs会话撤销支持按逻辑键批量操作IExternalAuthenticationSessionStore.RevokeActiveForConnectionAsync(connectionKey, reason, revokedAt)ExternalAuthenticationContracts.cs登录方法发现生成的LoginMethod携带Key其发起 URI 为/external-authentication/authorize/{connectionKey}DefaultIdentityProviderConnectionRegistry.cs。这意味着即使连接记录被覆盖、重建甚至归档后恢复已建立的 identity link 与长会话依然能通过逻辑键正确解析回同一逻辑连接这正是识别连续性identity continuity的实际收益。2.3 键的规范化与校验规则为了让键在不同来源间可比较源码定义了统一的规范化函数public static string NormalizeKey(string? key) key?.Trim().ToLowerInvariant() ?? string.Empty;见 ConnectionRevisionCalculator.cs。注册表内所有按键分组的操作候选分组、冲突检测、查找都基于NormalizeKey后的结果因此Google与google、 google 会被视为同一个逻辑键。管理服务同时校验键的合法性键必须非空、小写、URL 安全、长度不超过 128 字符、且不含空白字符IdentityProviderConnectionManagementService.cs。配置来源连接的Id则由作用域与逻辑键确定性派生public static string CalculateConfigurationConnectionId(ConnectionScope scope, string key) { var payload ${scope.Kind}\n{scope.TenantId}\n{NormalizeKey(key)}; var hash SHA256.HashData(Encoding.UTF8.GetBytes(payload)); return $configuration-{Convert.ToHexString(hash).ToLowerInvariant()}; }见 ConnectionRevisionCalculator.cs。该 ID 只是内部管理引用绝不是公开认证标识——这正是 ADR 所说的不把数据库行身份暴露为公开认证标识在实现层面的落地。三、配置基线 vs 显式覆盖完整替换绝不合并3.1 配置永远是部署基线ExternalAuthentication:Connections对应选项类中的ConfigurationConnections见 ExternalAuthenticationOptions.cs定义不可变的配置自有连接构成部署基线deployment baseline。任何环境变量、Kubernetes 挂载的配置、云密钥提供商等标准IConfiguration来源都可以作为其承载。3.2 显式覆盖是一个完整替换文档Studio 可以针对同一逻辑键创建一个显式持久化覆盖explicit persisted override但覆盖文档是完整的替换不合并任何字段——设置settings、密钥secrets、策略policy、展示presentation、生命周期lifecycle字段都不会跨来源合并。这是 ADR 0021 中最容易被误解、也最重要的语义。合并意味着继承对方的安全敏感字段如密钥绑定、claim 投影、上游登出策略会带来不可预测的安全与行为风险而完整替换让覆盖的边界清晰可审计覆盖里写了什么生效的就是什么。这一语义在源码中的承载是IdentityProviderConnection.OverridesConfigurationConnection布尔标记ExternalAuthenticationModels.cs。当数据库来源的连接携带该标记时它就是同键配置连接的显式覆盖。3.3 提升promotion与开关覆盖不是默认能力需要部署显式开启AllowConfigurationConnectionOverrides默认false控制数据库连接是否允许显式取代同键的配置连接见 ExternalAuthenticationOptions.cs管理服务中的CanCreateConfigurationOverride()与CanPromoteToConfigurationOverride(connection)分别判断能否创建覆盖与能否把某个被遮蔽的、未归档的数据库连接提升为覆盖IdentityProviderConnectionManagementService.cs校验层会拒绝非法覆盖OverridesConfigurationConnection true但部署未开启AllowConfigurationConnectionOverrides时返回not_allowed错误IdentityProviderConnectionManagementService.cs。提升操作会保留该数据库记录、其密钥绑定及其生命周期而不是新建一份文档同时若提升会移除最后一条正常登录路径FinalLoginPathGuard终局登录路径守卫默认启用见 ExternalAuthenticationOptions.cs会拒绝该变更。3.4 禁用仍遮蔽归档即还原ADR 0021 明确规定了两条容易被忽视的行为规则禁用disabled的覆盖仍然遮蔽基线覆盖文档的IsEnabled false只是让该逻辑连接在认证中不可用但遮蔽关系不变——配置基线不会因此浮出水面。此时该逻辑连接整体处于停用状态归档或删除覆盖 故意揭示配置连接ArchivedAt被设置或记录被删除后遮蔽解除配置基线的同键连接再次出现在生效注册表中恢复restore该覆盖则重新恢复完整遮蔽。这条遮蔽随覆盖文档生命周期走的规则在注册表实现中体现为显式覆盖的候选条件是Database 来源且OverridesConfigurationConnection true且ArchivedAt null见下文注册表源码。归档后的覆盖不再参与遮蔽判定配置连接自然重新可见。四、源码级印证生效注册表如何组合两个来源4.1 两个来源与优先级生效注册表由DefaultIdentityProviderConnectionRegistry构建DefaultIdentityProviderConnectionRegistry.cs输入是实现了IIdentityProviderConnectionSource的所有来源ConfigurationIdentityProviderConnectionSource来源名configuration所有权Configuration从当前ExternalAuthenticationOptions.ConfigurationConnections物化连接见 ConfigurationIdentityProviderConnectionSource.csDatabaseIdentityProviderConnectionSource来源名database所有权Database受EnableDatabaseConnections默认true门控从可替换的持久化存储读取行见 DatabaseIdentityProviderConnectionSource.cs。来源排序规则是GetOwnershipPriority配置所有权 0数据库所有权 1DefaultIdentityProviderConnectionRegistry.cs即配置优先于数据库这一 0015 的权威性约定被直接编码进排序。4.2 按规范化逻辑键分组并判定遮蔽注册表的组合算法DefaultIdentityProviderConnectionRegistry.cs核心逻辑如下var explicitOverride candidatesForKey.FirstOrDefault(x x.Source.Ownership ConnectionSourceOwnership.Database x.Connection is { OverridesConfigurationConnection: true, ArchivedAt: null }); var preferred explicitOverride ?? candidatesForKey.FirstOrDefault(x x.Source.Ownership ConnectionSourceOwnership.Configuration) ?? candidatesForKey.First();即对每个规范化逻辑键先把所有来源中作用域匹配的候选连接收集起来按NormalizeKey分组显式覆盖explicit override优先于一切数据库来源、OverridesConfigurationConnection true、且未归档若无显式覆盖则配置连接成为首选preferred其余同键候选被标记为遮蔽shadowed同时记录双向引用被遮蔽者持有ShadowedBy指向首选首选持有Shadows列出被它遮蔽的候选。生效连接模型EffectiveIdentityProviderConnection携带IsShadowed、ShadowedBy、Shadows以及来源名与所有权ExternalAuthenticationContracts.cs——这就是 ADR 所说的生效注册表同时报告来源provenance与遮蔽关系shadow relationship。4.3 可用性判定一个连接能否用于认证需同时满足DefaultIdentityProviderConnectionRegistry.cs!IsShadowed未被遮蔽Validity ! InvalidIsEnabled true且ArchivedAt null。注意被禁用与被归档是两个独立维度IsEnabledfalse的连接仍然存在但不可认证未归档的禁用覆盖依旧遮蔽配置基线归档则让记录退出遮蔽判定。4.4 版本指纹让遮蔽与覆盖的变化可被感知组合结果会计算一个版本指纹供缓存、会话材料修订material revision和连接测试观察使用每个连接物化后生成MaterialRevision前缀m-的 SHA-256 指纹见 ConnectionRevisionCalculator.cs覆盖了租户、键、适配器类型、适配器设置、密钥绑定、策略、grant 来源、claim 投影等全部材料字段注册表整体版本前缀r-由各来源快照版本组合而成ConnectionRevisionCalculator.cs一次性的连接测试观察记录TestedMaterialRevisionConnectionObservationExternalAuthenticationModels.cs一旦连接材料修订变化旧观察即告过期。因此管理员创建覆盖、归档覆盖、修改覆盖字段都会推动材料修订/注册表版本变化从而让依赖方会话校验、测试观察、Studio 界面能够感知配置基线是否重新浮出或遮蔽是否生效。五、典型配置示例下面是一个以appsettings.json形式表达的配置基线连接字段对应 ExternalAuthenticationOptions.cs 中Connections集合的选项属性{ ExternalAuthentication: { Connections: [ { key: google, adapterType: openid-connect, adapterSettingsVersion: 1, adapterSettings: { authority: https://accounts.google.com, clientId: elsa-google-client }, secretBindings: { clientSecret: { ownership: external, resolverType: configuration, reference: Secrets:ExternalAuthentication:GoogleClientSecret } }, displayName: Google, iconId: google, displayOrder: 1, isPreferred: true, isEnabled: true } ], EnableDatabaseConnections: true, AllowConfigurationConnectionOverrides: false } }要点说明key是逻辑键应使用小写、URL 安全的短 token≤128 字符不含空白运行时会被NormalizeKey再次规范化配置来源连接的OverridesConfigurationConnection恒为falseConfigurationIdentityProviderConnectionSource.cs即配置连接永远不会遮蔽自己也不表达覆盖EnableDatabaseConnections默认开启允许 Studio 维护数据库行AllowConfigurationConnectionOverrides默认关闭意味着默认情况下数据库行只能与配置同键共存为被遮蔽的冲突而不能取代配置若部署方希望允许 Studio 把某个被遮蔽的数据库记录提升为显式覆盖需要将AllowConfigurationConnectionOverrides设为true并注意FinalLoginPathGuard对移除最后一条正常登录路径的保护。更多外部认证注册、密钥绑定与安全默认值参见 Elsa.ExternalAuthentication README 与 外部认证快速上手。六、宿主级作用域与租户扩展点ADR 0021 明确宿主级host-wide连接管理并不取消 Elsa User 的租户体系。Identity Link 元组中的targetTenantId、会话中的TenantId、以及每个租户生效注册表的独立视图都说明外部身份与 Elsa 用户/租户授权仍然是两套正交概念与此相关的既有决策见 doc/adr/0017-separate-external-identity-from-elsa-authorization.md。源码中GetApplicableScopes()目前固定返回[ConnectionScope.Host]DefaultIdentityProviderConnectionRegistry.cs同时ConnectionScope已定义Host租户 ID*与DefaultTenant空串两类静态作用域ConnectionScopeKind还预留了Tenant枚举ExternalAuthenticationModels.cs——从源码结构看租户级连接是预留的扩展方向。但 ADR 0021 明确表示租户专属的连接管理tenant-specific connection administration在 v1 中被推迟。补充它需要一份显式的规范与迁移方案v1 不会预先建模 Deployment Target 实体也不会引入一个可编辑的鉴别器discriminator字段。当前注册表对跨作用域同键的处理是一旦同一逻辑键出现在多个作用域就将其标记为ConnectionValidity.Invalid并附带继承作用域冲突见 DefaultIdentityProviderConnectionRegistry.cs而不是尝试猜测归属。七、总结ADR 0021 为 Elsa 外部认证 v1 的连接身份管理定下三条边界清晰的规则识别靠逻辑键管理靠记录 ID不可变的ConnectionKey贯穿 identity link、长会话与登录方法发现数据库行 ID 只服务管理与瞬态流程绝不外露为公开认证标识覆盖是完整替换不是字段合并显式覆盖整文档取代配置基线禁用仍遮蔽、归档/删除才还原从而避免安全敏感字段跨来源继承也让每次变更可审计宿主级是 v1 的正式范围配置永远是最初基线数据库来源在EnableDatabaseConnections门控下可选参与AllowConfigurationConnectionOverrides显式放行覆盖能力租户级管理留待后续规范与迁移。这些规则并非只停留在文档层面而是完整落地于DefaultIdentityProviderConnectionRegistry的组合算法、ConnectionRevisionCalculator的规范化与版本指纹、以及管理服务的提升/校验/终局登录路径守卫中。对于部署方最需要记住的实操结论是要允许 Studio 覆盖配置连接先开AllowConfigurationConnectionOverrides覆盖文档必须自包含全部材料字段禁用覆盖不会让配置连接复活归档/删除才会。如需进一步深入可继续阅读doc/adr/0015-compose-a-scoped-connection-registry.md被部分取代的作用域与优先级决策、src/modules/Elsa.ExternalAuthentication/README.md配置所有权与密钥绑定总览、src/modules/Elsa.ExternalAuthentication/Services/DefaultIdentityProviderConnectionRegistry.cs 与 src/modules/Elsa.ExternalAuthentication/Services/ConnectionRevisionCalculator.cs组合与版本指纹实现。赞分享后端工作流自动化流程编排低代码【免费下载链接】elsa-coreThe Workflow Engine for .NET项目地址https://gitcode.com/gh_mirrors/el/elsa-core点击查看免费下载相关推荐gogcli focus-time功能详解用命令行自动圈出深度工作时间块gogcli focus time功能详解用命令行自动圈出深度工作时间块 gogcli 是一个把 Google Workspace 装进终端的命令行工具它的后端工作流自动化流程编排低代码Relay 连接Connection更新实战在 Mutation/Subscription 中增删边与连接身份管理Relay 连接Connection更新实战在 Mutation/Subscription 中增删边与连接身份管理 本指南聚焦 Relay 中的一个高频实前端开发工具Aspire 连接属性Connection Properties体系IResourceWithConnectionString 设计、属性目录与注入机制详解Aspire 连接属性Connection Properties体系IResourceWithConnectionString 设计、属性目录与注入机制详云原生后端微服务可观测性开发工具上一篇终极Windows右键菜单管理指南如何用ContextMenuManager告别菜单混乱下一篇Windows右键菜单革命告别臃肿打造极致效率的右键管理方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考