NocoBase EnvVariableInput 组件详解:面向 `$env` 环境变量的安全输入方案
2026/9/17 14:15:39 网站建设 项目流程

NocoBase EnvVariableInput 组件详解:面向$env环境变量的安全输入方案

【免费下载链接】nocobaseNocoBase is an open-source AI + no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase

EnvVariableInput是 NocoBase client-v2 中面向环境变量的单行输入组件,它只暴露$env命名空间,专门用于密钥、凭证、连接参数等敏感字段的配置。读完本文你将掌握该组件的完整用法、password遮盖模式的底层机制、值与{{ $env.X.Y }}表达式之间的双向转换原理,以及它如何与 environment-variables 插件协同工作。

组件定位与适用场景

在 NocoBase 的业务系统构建中,很多字段的值不应硬编码,而应引用部署环境提供的变量——例如 S3 的 Access Key、OAuth 的 client secret、SMTP 连接参数等。官方文档对EnvVariableInput的定位是:

EnvVariableInput是面向环境变量的输入组件。它只暴露$env命名空间,适合密钥、凭证和连接参数。

它本质上是通用 VariableInput 的受限变体:在源码 EnvVariableInput.tsx 中,组件内部以namespaces={ENV_NAMESPACES}(即['$env'])调用VariableInput,把变量选择器的可选范围牢牢限定在$env一棵树上,避免用户误选$user等其他命名空间的变量。

典型使用场景包括:

  • 表单中的密钥/凭证字段(Access Key Secret、API Key、OAuth Secret);
  • 连接参数(Base URL、SMTP 端口);
  • 任何「要么填字面值、要么引用环境变量」的单行短文本字段。

如果你需要字段同时支持类型化常量(数字、布尔、日期)和变量引用,请改用 TypedVariableInput;如果只是普通字面量输入,直接使用 Antd 原生Input即可。

基本用法

@nocobase/client-v2引入组件后,配合 AntdForm.Item即可直接使用:

import { EnvVariableInput } from '@nocobase/client-v2'; <Form.Item name={['options', 'accessKeySecret']} label={t('Access Key Secret')}> <EnvVariableInput password /> </Form.Item>;
  • name={['options', 'accessKeySecret']}将值嵌套存储在表单数据的options.accessKeySecret中;
  • password开启遮盖模式(详见下文);
  • 组件是受控组件,通过value/onChange与表单联动,因此也可以不依赖Form.Item单独使用。

仓库中的官方演示 env-variable-input.tsx 给出了一个更完整的形态:用initialValues预置{{ $env.ACCESS_KEY_SECRET }}表达式,配合placeholder="Input secret or select env variable"提示用户既可输入密钥字面值,也可选择环境变量:

import React from 'react'; import { Application, EnvVariableInput, Plugin } from '@nocobase/client-v2'; import { Form } from 'antd'; function DemoPage() { return ( <Form layout="vertical" style={{ maxWidth: 420 }} initialValues={{ accessKeySecret: '{{ $env.ACCESS_KEY_SECRET }}' }} > <Form.Item name="accessKeySecret" label="Access Key Secret"> <EnvVariableInput password placeholder="Input secret or select env variable" /> </Form.Item> </Form> ); }

password 模式:密钥遮盖的实现原理

password是该组件最具安全价值的能力。官方文档的描述是:

开启password后,非变量字面值会用 AntdInput.Password遮盖;变量表达式仍然可以通过变量选择器编辑。

也就是说,遮盖是有条件的。从源码 EnvVariableInput.tsx 可以看到完整判定逻辑:

const isVariableExpr = (value?: string) => typeof value === 'string' && /\{\{\s*[^{}]+?\s*\}\}/.test(value); if (password && rest.value && !isVariableExpr(rest.value)) { return ( <Input.Password disabled={rest.disabled} placeholder={rest.placeholder} value={rest.value} onChange={(event) => rest.onChange?.(event.target.value)} autoFocus /> ); } return <VariableInput {...rest} namespaces={ENV_NAMESPACES} converters={converters} />;

具体行为:

当前值password=falsepassword=true
字面值(如my-secret普通可编辑文本AntdInput.Password遮盖显示,可继续编辑
变量表达式(如{{ $env.API_KEY }}渲染为变量 pill,可编辑仍渲染为变量 pill,不被遮盖,仍可通过变量选择器编辑

这套行为被测试用例 EnvVariableInput.test.tsx 严格验证:明文值my-secretpassword下输入框的type属性为password;而{{ $env.API_KEY }}password=true时依旧以带nb-variable-tag样式的 pill 展示,且不会以明文文本出现。

这样设计的原因很直观:变量表达式本身不包含敏感信息,只是对$env树上某个键的引用,真正敏感的是被引用的值(存储于服务端);而用户在输入框里直接敲入的明文密钥才需要遮盖保护。

API 一览

官方文档给出的完整参数如下:

参数类型说明
valuestring当前值
onChange(value: string) => void值变化回调
addonBeforeReact.ReactNode前置内容
disabledboolean是否禁用
passwordboolean是否遮盖非变量字面值
placeholderstring占位文字

从源码 EnvVariableInputProps 可以看到这些 props 与接口一一对应。其中disabled在两种渲染分支(Input.Password与变量编辑器)下都会生效:测试 EnvVariableInput.test.tsx 验证了禁用时编辑器contenteditablefalseplaceholder在变量编辑分支下会映射到data-placeholder属性(见测试 L156-L164)。

值格式:{{ $env.X.Y }}与变量的双向转换

EnvVariableInput存储的值是形如{{ $env.ACCESS_KEY_SECRET }}{{ $env.foo.bar }}的字符串——这是 NocoBase 服务端模板(Handlebars 风格)兼容的表达式格式。为了让变量选择器的内部路径表示(如['$env', 'foo', 'bar'])与存储字符串互相转换,组件导出了两个工具函数,并作为converters注入底层VariableHybridInput

parseEnvPath:字符串 → 路径数组

源码 parseEnvPath 只接受「整个输入恰好是一个$env表达式」的情况(锚定正则^\{\{\s*(\$env\.[^{}]+?)\s*\}\}$),并将其拆分为路径:

parseEnvPath('{{ $env.API_KEY }}') // => ['$env', 'API_KEY'] parseEnvPath('{{ $env.foo.bar.baz }}') // => ['$env', 'foo', 'bar', 'baz'] parseEnvPath(' {{ $env.API_KEY }} ') // => ['$env', 'API_KEY'](自动去空白) parseEnvPath('plain value') // => undefined parseEnvPath('{{ $user.name }}') // => undefined(非 $env 命名空间) parseEnvPath('prefix {{ $env.API_KEY }}') // => undefined(混合内容) parseEnvPath('') // => undefined

以上行为在测试 EnvVariableInput.test.tsx 中逐一断言。注意「混合内容」(前缀/后缀夹杂变量)会被判定为 undefined,这正是单行纯变量输入与 VariableTextArea 多行自由文本输入的区别。

formatEnvPath:路径数组 → 字符串

formatEnvPath 负责把变量选择器选中的 meta tree 节点还原为服务端可用的表达式,保证值「经 API 往返后字节稳定」:

formatEnvPath({ paths: ['$env', 'API_KEY'] }) // => '{{ $env.API_KEY }}' formatEnvPath({ paths: ['$env', 'foo', 'bar'] }) // => '{{ $env.foo.bar }}' formatEnvPath({ paths: ['$user', 'name'] }) // => undefined(拒绝非 $env) formatEnvPath({ paths: ['$env'] }) // => undefined(仅有根节点) formatEnvPath(undefined) // => undefined

函数会先检查paths[0] !== '$env' || paths.length < 2,只有选中了$env下至少一级属性时才会生成表达式(测试见 L81-L102)。这两个转换器连同ENV_EXPR_REGEXP(全局匹配$env变量用于渲染 pill)一起,由组件通过useMemo构造并注入VariableInput

const converters = useMemo<VariableHybridInputConverters>( () => ({ formatPathToValue: formatEnvPath, parseValueToPath: parseEnvPath, variableRegExp: ENV_EXPR_REGEXP, }), [], );

这种「自定义 converters 收敛到单一命名空间」的模式,正是VariableInput文档中converters参数所描述的典型用途(见 variable-input.md)。

底层依赖:$env变量树从哪来

EnvVariableInput本身不产生变量数据,它消费的是 flow-engine context 上的$env属性树。组件源码注释明确指出:

The$envtree is provided by the environment-variables plugin'sflowEngine.context.defineProperty('$env', ...); this component degrades gracefully to an empty picker when no env variables are defined.

也就是说,当环境中没有定义任何环境变量时,变量选择器打开后为空,组件仍可正常用于输入字面值——这是「优雅降级」设计。

$env树的注册逻辑位于 environment-variables 插件,见 registerEnvProperty.ts。核心要点:

  • 数据来源:通过 APIenvironmentVariables?paginate=false惰性拉取环境变量列表(首次读取时请求,并由 flow-engine context 缓存,选择器展开时不会重复请求);
  • meta 树结构:每个变量名对应一个{ type: 'string', title: name }的属性节点,其中type: 'secret'的变量也被建模为字符串类型;
  • 框架无关:该注册函数不依赖 React hooks 或@nocobase/client,通过参数注入apiClient和翻译函数t,可同时服务于 client-v2 与 v1 两套运行时。

服务端对应的数据集合定义在 environmentVariables.ts,包含三个字段:

字段类型说明
namestring(主键)变量名,需匹配^[A-Za-z][A-Za-z0-9_]*$(见 re.ts)
typestringdefaultsecret
valuetext变量值

变量名只能以字母开头、由字母数字下划线组成,这个约束保证了{{ $env.X.Y }}表达式能被可靠解析。字段命名空间中$env这个约定也贯穿于 flow-engine 的工作流变量选项,例如 useWorkflowVariableOptions.tsx 中同样会读取该属性树。

实战建议

  1. 密钥字段务必开启passwordaccessKeySecretapiKeyoauthSecret这类字段直接加password属性,明文字面值会被Input.Password遮盖;
  2. 值优先用表达式而非明文:在 environment-variables 插件 中先定义好变量,再在表单里通过变量选择器引用{{ $env.XXX }},让密钥只存在于服务端;
  3. 注意变量命名约束:环境变量名必须匹配^[A-Za-z][A-Za-z0-9_]*$,含连字符或中文的键无法注册;
  4. 理解降级行为:未安装/未启用 environment-variables 插件,或变量列表为空时,选择器为空但不影响字面值输入;
  5. 区分兄弟组件:纯字面量用 AntdInput,纯$env变量用EnvVariableInput,通用变量用 VariableInput,常量+变量混合用 TypedVariableInput,多行模板文本用 VariableTextArea。

相关链接

  • VariableInput — 通用单行变量输入
  • TypedVariableInput — 同时支持常量和变量
  • 组件源码 与 单元测试
  • $env 变量注册实现 与 数据集合定义
  • 官方演示 Demo

【免费下载链接】nocobaseNocoBase is an open-source AI + no-code platform for building business systems fast. Instead of generating everything from scratch, AI works on top of production-proven infrastructure and a WYSIWYG no-code interface, so you get both speed and reliability.项目地址: https://gitcode.com/GitHub_Trending/no/nocobase

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询