ARTICLE DETAIL

资讯详情

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

HarmonyOS 7 Asset Store Kit + ArkTS:登录 Token 双槽轮换中的新旧凭据切换、查询条件校验与延迟清理【鸿蒙心迹】

HarmonyOS 7 Asset Store Kit + ArkTS:登录 Token 双槽轮换中的新旧凭据切换、查询条件校验与延迟清理【鸿蒙心迹】 以前做 Token 轮换我会直接覆盖旧值。后来在“新 token 写入”和“业务切换”之间注入异常发现旧 token 已删而新 token 因查询条件不完整没有真正被业务读到。CredentialRotationLab处理轮换顺序新凭据先入库验证通过后再切 active alias旧凭据延迟删除。一、为什么不是直接更新数据cred_rotate_20261001_12、ACTIVE_V12、Active Aliassession_token_v12、Old Aliassession_token_v11、Generation12、Query Matches1、ValidationPASS、Cleanup Pendingfalse、Old Removed1、Last Switch12:07:44。凭据使用 A/B 两个槽位。session_token_v11原来是 ACTIVE先创建session_token_v12作为 STANDBY查询和 generation、userId 校验通过后再切换入口。新凭据失败时旧凭据仍可用。二、先新增新槽位不覆盖旧槽位Asset Store Kit 适合保存 Token 等短敏感数据。Demo 中新 token 使用新 alias 写入。import { asset } from kit.AssetStoreKit import { util } from kit.ArkTS private encoder: util.TextEncoder new util.TextEncoder() private bytes(text: string): Uint8Array { return this.encoder.encodeInto(text) } async saveToken( alias: string, token: string, generation: number, userId: string ): Promisevoid { const attrs: asset.AssetMap new Map() attrs.set(asset.Tag.SECRET, this.bytes(token)) attrs.set(asset.Tag.ALIAS, this.bytes(alias)) attrs.set( asset.Tag.ACCESSIBILITY, asset.Accessibility.DEVICE_FIRST_UNLOCKED ) attrs.set( asset.Tag.DATA_LABEL_NORMAL_1, this.bytes(userId) ) attrs.set( asset.Tag.DATA_LABEL_NORMAL_2, this.bytes(String(generation)) ) await asset.add(attrs) }alias 直接带版本session_token_v11、session_token_v12。业务 label 只存 userId、generationtoken 放在SECRET。三、查询时 RETURN_TYPE 不能省这个坑很具体。只按 ALIAS 查询却没设置返回类型时调用可能不报错但业务拿不到期望结果所以查询统一封装。async queryByAlias( alias: string ): PromiseArrayasset.AssetMap { const query: asset.AssetMap new Map() query.set( asset.Tag.ALIAS, this.bytes(alias) ) query.set( asset.Tag.RETURN_TYPE, asset.ReturnType.ALL ) const result await asset.query(query) hilog.info( 0x0000, TokenAssetStore, query matches${result.length} returnTypeALL ) return result }本轮Query Matches1。随后校验user_10086和 generation 12返回 0 条、命中多条或 generation 不对都不切 active。四、active alias 的切换位置不能提前轮换关键是顺序。async rotate(newToken: string): Promisevoid { const oldAlias session_token_v11 const newAlias session_token_v12 this.state STANDBY_V12 await this.store.saveToken( newAlias, newToken, 12, user_10086 ) this.state VALIDATING const list await this.store.queryByAlias(newAlias) if (list.length ! 1) { throw new Error(new credential not found) } const generation this.store.readGeneration(list[0]) if (generation ! 12) { throw new Error(generation mismatch: ${generation}) } this.validation PASS this.activeAlias newAlias this.state SWITCHED await this.scheduleOldCredentialCleanup(oldAlias) this.state ACTIVE_V12 }active alias 只在查询和校验通过后切换。正式项目还应持久化当前 generation。五、旧凭据为什么延迟删除新 token 切换成功后我也没有立刻删 v11。一些请求可能已经带着旧 token 发出如果切换后立刻删除旧凭据重试链路会变脆。Demo 用短延迟模拟清理窗口private async scheduleOldCredentialCleanup( oldAlias: string ): Promisevoid { this.cleanupPending true await new Promisevoid((resolve) { setTimeout(() resolve(), 3000) }) const query: asset.AssetMap new Map() query.set( asset.Tag.ALIAS, this.store.bytes(oldAlias) ) await asset.remove(query) this.oldRemoved this.cleanupPending false }setTimeout只用于 Demo 展示顺序。正式项目若清理跨后台或跨进程应保存“旧 alias 待清理”状态再在安全时机完成。本轮最终Cleanup Pendingfalse、Old Removed1。六、日志要能解释一次完整轮换项目结构只保留页面、轮换协调器、Asset Store 封装和槽位模型。HiLog 固定输出add aliassession_token_v12 gen12 query matches1 returnTypeALL validate generation12 PASS switch active alias - v12 remove old aliasv11 State: VALIDATING - ACTIVE_V12七、最终结果要同时看“新可用”和“旧已清”手机页面里StateACTIVE_V12Active Aliassession_token_v12Old Aliassession_token_v11Generation 12ValidationPASSCleanup PendingfalseOld Removed 1。Slot A 已 REMOVEDSlot B 为 ACTIVE。查询区保留RETURN_TYPEALL、matches1、userIduser_10086。八、失败路径比成功路径更值得设计新增失败、查询异常或 generation 不对时都不切 active。切到 v12 后若旧凭据删除失败只保留清理任务不再切回 v11。九、双槽轮换的核心是不要过早破坏旧状态最终链路是ACTIVE_V11 → STANDBY_V12 → VALIDATING → SWITCHED → ACTIVE_V12Asset Store Kit 提供安全存储能力稳定性取决于写入、查询、切换和清理顺序。对于Token双槽轮换虽然更长却更容易保住最后一个可用状态。
返回列表