主题
安全存储
一项用于安全存储敏感键值数据的服务,它使用各平台原生的安全存储机制 —— iOS/macOS 上的 Keychain、Windows Credential Manager、Linux 上的 libsecret,以及 Android 上的 Keystore。
由 Flutter 的 flutter_secure_storage 包提供支持。
INFO
构建项目时机器上需要有 libsecret-1-dev,运行应用时需要 libsecret-1-0(打包应用后将其添加为依赖)。如果你使用 snapcraft 构建项目,请按下面的方式操作。
除 libsecret 之外,你还需要一个密钥环服务:Gnome 用户可用 gnome-keyring,KDE 用户可用 kwalletmanager,或者使用 secret-service 这类更轻量的提供者。
bash
sudo apt-get install libsecret-1-dev libsecret-1-0平台支持
| 平台 | Windows | macOS | Linux | iOS | Android | Web |
|---|---|---|---|---|---|---|
| 支持 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
用法
将 flet-secure-storage 添加到项目依赖:
uv
bash
uv add flet-secure-storagepip
bash
pip install flet-secure-storage [^1][^1]: 之后,你需要手动将此包添加到你的 requirements.txt 或 pyproject.toml。
示例
python
import base64
import os
import flet as ft
import flet_secure_storage as fss
def main(page: ft.Page):
page.vertical_alignment = ft.MainAxisAlignment.CENTER
page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
storage = fss.SecureStorage(
web_options=fss.WebOptions(
db_name="customstorage",
public_key="publickey",
wrap_key=base64.urlsafe_b64encode(os.urandom(32)).decode(),
wrap_key_iv=base64.urlsafe_b64encode(os.urandom(16)).decode(),
),
android_options=fss.AndroidOptions(
reset_on_error=True,
migrate_on_algorithm_change=True,
enforce_biometrics=True,
key_cipher_algorithm=fss.KeyCipherAlgorithm.AES_GCM_NO_PADDING,
storage_cipher_algorithm=fss.StorageCipherAlgorithm.AES_GCM_NO_PADDING,
),
)
key = ft.TextField(label="Key", value="example_key")
value = ft.TextField(label="Value", value="secret_value")
result = ft.Text(theme_style=ft.TextThemeStyle.TITLE_LARGE)
async def set_value(e):
await storage.set(key.value, value.value)
result.value = "Value saved"
async def get_value(e):
result.value = await storage.get(key.value)
async def remove_value(e):
await storage.remove(key.value)
result.value = "Value removed"
async def clear_storage(e):
await storage.clear()
result.value = "Storage cleared"
async def contains_key(e):
exists = await storage.contains_key(key.value)
result.value = f"Key exists: {exists}"
async def get_availability(e):
is_availability = await storage.get_availability()
page.show_dialog(
ft.SnackBar(
content=ft.Text(
value=f"Protected data available: {is_availability}"
if is_availability
else "Protected data available: None"
)
)
)
page.add(
ft.SafeArea(
content=ft.Column(
controls=[
ft.Column(
alignment=ft.MainAxisAlignment.CENTER,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
spacing=10,
controls=[
result,
key,
value,
ft.Row(
width=300,
wrap=True,
controls=[
ft.Button("Set", on_click=set_value),
ft.Button("Get", on_click=get_value),
ft.Button("Contains key", on_click=contains_key),
ft.Button("Remove", on_click=remove_value),
ft.Button("Clear", on_click=clear_storage),
ft.Button(
"Check Data Availability",
on_click=get_availability,
),
],
),
],
)
],
),
)
)
if __name__ == "__main__":
ft.run(main)说明
SecureStorage 继承自:Service, BaseControl
一个用于在 Flet 应用中跨多个平台管理安全存储的类。
属性
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
ios_options | IOSOptions | IOSOptions(() | 针对 iOS 的安全存储配置。 |
android_options | AndroidOptions | AndroidOptions(() | 针对 Android 的安全存储配置。 |
windows_options | WindowsOptions | WindowsOptions(() | 针对 Windows 的安全存储配置。 |
macos_options | MacOsOptions | MacOsOptions(() | 针对 macOS 的安全存储配置。 |
web_options | WebOptions | WebOptions(() | 针对 Web 的安全存储配置。 |
data | Any | skip_ | 任意类型的自定义数据。 |
key | Optional['KeyValue'] | None | 用于在更新之间保持控件标识稳定的键。 |
只读属性
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
parent | Optional['BaseControl'] | — | 此控件的直接祖先(父级)。 默认为 None,只有在此控件被挂载(加入页面树)后才有值。 Page 控件(页面树的根)是个例外 —— 它的 parent 始终为 None。 |
page | 'Page' | — | 此控件所属的页面。 |
事件
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
on_change | Optional[ft.EventHandler['SecureStorageEvent']] | None | 当安全存储的可用性发生变化时触发。 仅限 iOS 功能。对于不支持的平台,此事件永远不会触发。其载荷是一个 SecureStorageEvent 对象,包含 available 字段。 |
方法
| 名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|
get_availability | Optional[bool] | — | 获取安全存储当前的可用性状态。 仅限 iOS 和 macOS。在 macOS 上仅 macOS 12+ 可用。在更早的 macOS 版本上始终返回 True。在不支持的平台上返回 None。 返回: 表示存储可用性的布尔值;若不支持则返回 None。 |
set | None | — | 在安全存储中存储给定键的值。 参数: key:用于存储值的键。 value:要存储的值(不能为 None)。 web:可选的 Web 专用配置。 ios:可选的 iOS 专用配置。 macos:可选的 macOS 专用配置。 android:可选的 Android 专用配置。 windows:可选的 Windows 专用配置。 抛出异常: ValueError:如果 value 为 None。 |
get | Optional[str] | — | 检索安全存储中给定键下存储的值。 参数: key:要检索的键。 web:可选的 Web 专用配置。 ios:可选的 iOS 专用配置。 macos:可选的 macOS 专用配置。 android:可选的 Android 专用配置。 windows:可选的 Windows 专用配置。 返回: 已存储的字符串值;如果键不存在则返回 None。 |
get_all | dict[str, str] | — | 检索安全存储中的所有键值对。 参数: web:可选的 Web 专用配置。 ios:可选的 iOS 专用配置。 macos:可选的 macOS 专用配置。 android:可选的 Android 专用配置。 windows:可选的 Windows 专用配置。 返回: 包含所有已存储键值对的字典。 |
contains_key | bool | — | 检查给定的键是否存在于安全存储中。 参数: key:要检查的键。 web:可选的 Web 专用配置。 ios:可选的 iOS 专用配置。 macos:可选的 macOS 专用配置。 android:可选的 Android 专用配置。 windows:可选的 Windows 专用配置。 返回: 如果键存在则返回 True,否则返回 False。 |
remove | None | — | 移除安全存储中给定键下存储的值。 参数: key:要移除的键。 web:可选的 Web 专用配置。 ios:可选的 iOS 专用配置。 macos:可选的 macOS 专用配置。 android:可选的 Android 专用配置。 windows:可选的 Windows 专用配置。 |
clear | None | — | 清除安全存储中的所有键值对。 参数: web:可选的 Web 专用配置。 ios:可选的 iOS 专用配置。 macos:可选的 macOS 专用配置。 android:可选的 Android 专用配置。 windows:可选的 Windows 专用配置。 |
init | — | — | — |
is_isolated | — | — | 返回此控件是否被标记为隔离。 隔离控件会被排除在父级驱动的更新遍历之外,并需要自行管理更新边界。 |
build | — | — | 在控件初始化期间调用一次,用于定义其子控件。在此方法中 page 属性可用。 |
before_update | — | — | 每当此控件被更新时都会调用此方法。 注意: 务必不要在此处调用或请求 update()。 |
before_event | — | — | 在事件处理器执行之前拦截事件。 返回 False 可取消分发。返回 True 或 None 则继续正常的事件处理。 |
did_mount | — | — | 在控件挂载到页面树之后调用。 重写此方法以启动需要已挂载页面的资源,例如订阅、定时器或服务监听器。 |
will_unmount | — | — | 在控件从页面树移除之前调用。 重写此方法以释放 did_mount() 中创建的资源,例如订阅、定时器或外部句柄。 |
get_data_channel | — | — | 解析为此 widget 在 Dart 侧分配的 [DataChannel]。模式: on_data_channel_open: Optional[ft.EventHandler[DataChannelOpenEvent]] = None def init(self): self.on_data_channel_open = self._on_open def _on_open(self, e): self._channel = self.get_data_channel(e.channel_id) 幂等 —— 底层的 Connection 会按 id 缓存 DataChannel,因此重复调用会返回同一实例。没有错误路径:该 id 始终来自框架触发的事件,所以当此方法运行时,通道在两端都已存在。 |
update | None | — | 为此控件请求一次 UI 更新。 在更改控件状态或属性后调用。控件必须已挂载到页面且未被标记为冻结。 |