ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Fleet 与 Google Workspace 集成:利用自定义属性与 Apps Script 自动同步用户全名

2026/9/17 16:51:07 拓冰建站 浏览量
Fleet 与 Google Workspace 集成:利用自定义属性与 Apps Script 自动同步用户全名 Fleet 与 Google Workspace 集成利用自定义属性与 Apps Script 自动同步用户全名【免费下载链接】fleetOpen device management项目地址: https://gitcode.com/GitHub_Trending/fl/fleetFleet 在 SSO 登录时需要从 IdP 的 SAML 响应中读取用户全名但 Google Workspace 默认并不暴露与 Fleet 识别规则匹配的 full name 属性。本文以 官方指南 为主体完整讲解如何通过 Google 自定义属性 Apps Script 定时任务 SAML 属性映射三步打通这一链路并结合 Fleet 服务端源码说明全名属性的解析逻辑读完即可在自己的 Fleet 实例上落地该方案。背景与要解决的问题Fleet 在用户通过 SSO 登录包括 JIT 用户自动创建、macOS 首次设置体验中创建本地账户时需要从 SAML 断言中找出用户的 full name。它只认以下这组属性名namedisplaynamecnurn:oid:2.5.4.3http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name这一点在仓库的 SSO 部署文档中有明确记载docs/Deploy/single-sign-on-sso.md 指出IdP 必须把用户全名以这五个名称之一作为属性下发如果该值未提供Fleet 将回退使用用户邮箱Fleet will fall back to the user email。而 Google Workspace 的目录属性中并没有直接暴露上述任何一个属性给 SAML 应用因此需要完成三件事在 Google Workspace 中创建一个自定义属性来存放全名编写脚本自动把每个用户的姓名givenName familyName写入该属性在 SAML 应用配置中把该自定义属性映射为 Fleet 可识别的属性名如name。Fleet 服务端如何识别全名属性源码佐证从源码结构看上述五个属性名并非散落在各处而是集中在一个白名单中。server/sso/authorization_response.go 定义了该映射var validDisplayNameAttrs map[string]struct{}{ name: {}, displayname: {}, cn: {}, urn:oid:2.5.4.3: {}, http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name: {}, }注释说明这些名称的来源是 LDAP RFC 2798 与 Microsoft AD FS 的 claim 约定因为显示名本身并没有行业标准。真正的提取逻辑在同文件的UserDisplayName()方法中server/sso/authorization_response.gofunc (r resp) UserDisplayName() string { if r.assertion nil { return } for _, attrStatement : range r.assertion.AttributeStatements { for _, attr : range attrStatement.Attributes { if _, ok : validDisplayNameAttrs[strings.ToLower(attr.Name)]; ok { for _, vv : range attr.Values { if vv.Value ! { return vv.Value } } } } } return }有三个对集成方很重要的细节属性名匹配是大小写不敏感的strings.ToLower(attr.Name)意味着 Google 侧映射成Name或NAME也能被识别但为稳妥起见仍建议使用全小写的name只取第一个非空值一旦在某个命中属性中取到非空值即返回不会合并多个属性的值找不到时返回空字符串此时上层逻辑回退到用户邮箱。这一点与 server/fleet/sessions.go 中Auth接口对UserDisplayName()的注释一致——there isnt a defined spec for this, so the return value is in a best-effort basis。该行为有对应测试覆盖server/sso/authorization_response_test.go 中的TestUserDisplayName用表驱动用例验证了各属性名含大小写变体的提取结果可作为映射配置是否生效的参照标准。前置条件Google Workspace 管理员权限Admin access对 Google Admin Console 的基本操作了解一个已完成 SAML 认证配置的 Fleet 实例。第一步在 Google Workspace 中创建自定义属性先为全名数据准备存放位置登录 Google Admin Consoleadmin.google.com进入Directory目录Users用户点击右上角的More options更多选项三个点图标选择Manage custom attributes管理自定义属性点击Add Custom Attribute添加自定义属性填写以下内容Category name类别名Fleet必须与第二步脚本中的类别名完全一致Description描述Attributes for Fleet integration在Custom fields自定义字段下添加一个字段Name名称FullnameInfo type信息类型TextMulti-value多值不勾选Visibility可见性Visible to user and admin用户和管理员可见点击Add添加。类别名Fleet与字段名Fullname是后续脚本写入和 SAML 映射的锚点任何一步中名称不一致都会导致属性丢失这也是原文档 Troubleshooting 中专门提醒的一点。第二步创建 Google Apps Script 填充该属性接下来创建一个脚本自动把每个用户的全名写入Fleet.Fullname自定义属性打开 Google Apps Scriptscript.google.com点击New Project创建新项目删除编辑器中的模板代码粘贴以下代码/** * Updates all users in Google Workspace with their full name in the Fleet.Fullname custom attribute. * This attribute can then be mapped in SAML configurations for Fleet integration. */ function updateFullnames() { const users AdminDirectory.Users.list({customer: my_customer}).users; users.forEach(user { const fullName ${user.name.givenName} ${user.name.familyName}.trim(); // Update custom schema using Fleet category and Fullname attribute const customSchemas { Fleet: { Fullname: fullName } }; try { AdminDirectory.Users.update( {customSchemas: customSchemas}, user.primaryEmail ); console.log(Updated ${user.primaryEmail} with full name: ${fullName}); } catch (error) { console.log(Error updating ${user.primaryEmail}: ${error}); } }); } /** * Creates a daily trigger to run the updateFullnames function. * Run this function once to set up the automatic daily updates. */ function createTrigger() { // Check if trigger already exists const triggers ScriptApp.getProjectTriggers(); const triggerExists triggers.some(trigger trigger.getHandlerFunction() updateFullnames trigger.getEventType() ScriptApp.EventType.CLOCK ); // Only create a new trigger if one doesnt already exist if (!triggerExists) { ScriptApp.newTrigger(updateFullnames) .timeBased() .everyDays(1) .create(); console.log(Daily trigger created successfully); } else { console.log(Daily trigger already exists); } }脚本要点AdminDirectory.Users.list({customer: my_customer})拉取当前租户下的全部用户全名由givenName与familyName拼接而成.trim()用于处理某一部分为空时的多余空格通过AdminDirectory.Users.update以primaryEmail为定位键写入customSchemas这正是第一步创建的Fleet.Fullname字段createTrigger先检查是否已存在名为updateFullnames的 CLOCK 类型触发器避免重复创建保证幂等。通过FileSave保存项目命名如 Fleet Full Names点击左侧边栏 Services 旁的图标向下滚动选择Admin SDK API点击Add添加。第三步运行脚本并建立自动同步在 Apps Script 编辑器中从 Run 按钮旁的下拉框中选择updateFullnames函数点击Run按提示完成授权点击 Review Permissions查看权限选择你的 Google 账户点击 Allow允许 授予所需权限脚本运行后会遍历并更新所有用户的全名属性接着从下拉框中选择createTrigger函数再次点击Run至此每日定时任务建立完成全名属性将持续保持同步。第四步配置 SAML 属性映射最后一步是把自定义属性映射到 Fleet 可识别的属性名上回到 Google Admin Consoleadmin.google.com进入Apps应用Web and mobile appsWeb 和移动应用找到你的 Fleet SAML 应用若尚未添加则先添加进入SAML Attribute MappingSAML 属性映射区域点击ADD MAPPING添加映射配置映射Google Directory AttributeGoogle 目录属性在 Custom Attributes 下选择Fleet FullnameApp Attribute应用属性填写name也可用其他受支持名称如displayname点击SAVE保存。映射为name后Fleet 侧的UserDisplayName()会命中 server/sso/authorization_response.go 白名单中的name键完成从 Google 自定义属性到 Fleet 用户显示名的最后一公里。验证确认整条链路工作正常在 Google Admin Console 中检查某个用户的自定义属性是否已填充进入DirectoryUsers点击某个用户找到Fleet区域确认Fullname已有值触发一次对 Fleet 的 SAML 登录验证属性被正确下发在 macOS 设备入网initial setup experience时检查本地账户的全名是否被正确填充。如需确认 SAML 断言中的实际属性可以参考 server/sso/authorization_response_test.go 中TestUserDisplayName用例所模拟的断言结构——它演示了不同属性名含大小写变体下UserDisplayName()的期望输出是判断映射后的属性名是否能被 Fleet 识别的权威依据。故障排查遇到问题时按以下线索排查脚本错误点击 Apps Script 左侧边栏的Executions查看执行日志属性缺失核对脚本中的Fleet/Fullname与 SAML 映射中选择的属性名是否完全一致类别名、字段名区分大小写SAML 问题登录时使用 Chrome 开发者工具检查 SAML 响应SAMLResponse 为 base64 编码Fleet 侧在 server/sso/authorization_response.go 的DecodeSAMLResponse中做解码解码后确认 AttributeStatement 中是否携带了映射的属性权限不足确认操作账户具有足够的管理员权限。日常维护脚本每天自动运行一次以保持全名最新。若修改过脚本可能需要重新授权通过左侧边栏的Executions查看日志通过左侧边栏的Triggers管理触发器。新加入 Google Workspace 的用户会在下一个每日同步周期中被自动纳入。小结该方案通过自定义属性 Apps Script 定时写入 SAML 映射三段式结构弥补了 Google Workspace 不暴露 Fleet 所需全名属性的缺口。理解 Fleet 侧 server/sso/authorization_response.go 中validDisplayNameAttrs白名单与大小写不敏感的匹配逻辑后你可以确认映射目标必须落在五个受支持名称之内而 docs/Deploy/single-sign-on-sso.md 中关于 JIT 用户创建的说明则提示配置完成后用户首次 SSO 登录时 Fleet 自动创建的账户将直接使用同步好的全名而非回退为邮箱macOS 初始设置体验中的本地账户命名也随之正确。【免费下载链接】fleetOpen device management项目地址: https://gitcode.com/GitHub_Trending/fl/fleet创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考