本文原创发布在华为开发者社区。
介绍
本示例基于关键资产存储服务API实现了免密登录功能。
效果预览
使用说明
注意,设备需设置锁屏密码后才可使用免密登录功能。
输入账号和密码,勾选“记住密码”,底部会出现提示弹窗,点击“登录”按钮后,点击“重新加载该页面”,会出现输入锁屏密码的弹窗,输入成功,应用自动填充账号和密码。
实现思路
保存账户信息
通过asset.add接口保存用户信息,此处设置了访问该信息需要通过用户认证,仅在设置锁屏密码且解锁的情况下可访问关键资产。通过promptAction.showToast接口实现记住密码的文字弹窗。核心代码如下,源码参考
Index.ets
getAccountLoginInfo() {
const accountInfo: IAccountInfo = {
name: this.accountName,
password: this.accountPassword
}
const attrInfo: asset.AssetMap = new Map()
// 需要存储的关键资产数据
attrInfo.set(asset.Tag.SECRET, this.stringToBuffer(JSON.stringify(accountInfo)))
// 数据别名
attrInfo.set(asset.Tag.ALIAS, this.stringToBuffer(this.accountAlias))
// 解锁状态时可访问
attrInfo.set(asset.Tag.ACCESSIBILITY, asset.Accessibility.DEVICE_UNLOCKED)
// 仅在设置锁屏密码的情况下,可访问关键资产
attrInfo.set(asset.Tag.REQUIRE_PASSWORD_SET, true)
// 需要开启通过用户认证后,才访问关键资产
attrInfo.set(asset.Tag.AUTH_TYPE, asset.AuthType.ANY)
// 新增关键资产时已存在数据,则覆盖
attrInfo.set(asset.Tag.CONFLICT_RESOLUTION, asset.ConflictResolution.OVERWRITE)
return attrInfo
}
查询账户信息
查询账户信息需要通过用户认证,分为以下两个步骤进行。
调用asset.preQuery接口获取challenge。
async preAccountInfo() { const queryInfo: asset.AssetMap = new Map() queryInfo.set(asset.Tag.ALIAS, this.stringToBuffer(this.accountAlias)) // 用户认证token有效期30s queryInfo.set(asset.Tag.AUTH_VALIDITY_PERIOD, 30) try { // step1 const challenge = await asset.preQuery(queryInfo) // step2 this.startUserAuth(challenge) } catch (e) { console.error(TAG, `查询账号登录信息失败 ${e.code} ${e.message}`) } }
调用用户认证接口,认证通过调用asset.query查询数据,最后调用asset.postQuery接口结束查询。
a)拉起用户认证startUserAuth(challenge: Uint8Array) { const authParam: userAuth.AuthParam = { challenge, authType: [userAuth.UserAuthType.PIN, userAuth.UserAuthType.FINGERPRINT], authTrustLevel: userAuth.AuthTrustLevel.ATL1 } const widgeParam: userAuth.WidgetParam = { title: '请输入密码' } const userAuthInstance = userAuth.getUserAuthInstance(authParam, widgeParam) userAuthInstance.on('result', { onResult: async (data) => { // 认证成功 if (data.result === userAuth.UserAuthResultCode.SUCCESS) { // step3 await this.queryAccountInfo(data.token, challenge) // step4 const handle: asset.AssetMap = new Map() handle.set(asset.Tag.AUTH_CHALLENGE, challenge) await asset.postQuery(handle) promptAction.showToast({ message: '获取账户信息成功' }) } } }) userAuthInstance.start() }
b)查询数据
async queryAccountInfo(token: Uint8Array, challenge: Uint8Array) { const query: asset.AssetMap = new Map() query.set(asset.Tag.ALIAS, this.stringToBuffer(this.accountAlias)) query.set(asset.Tag.AUTH_TOKEN, token) query.set(asset.Tag.AUTH_CHALLENGE, challenge) query.set(asset.Tag.RETURN_TYPE, asset.ReturnType.ALL) try { const data: Array<asset.AssetMap> = await asset.query(query) if (data.length) { const map = data.shift()! as asset.AssetMap const secret = map.get(asset.Tag.SECRET) as Uint8Array const accountInfo: IAccountInfo = JSON.parse(this.bufferToString(secret)) this.accountName = accountInfo.name this.accountPassword = accountInfo.password } else { console.error(TAG, `没有查询到数据`) } } catch (e) { console.error(TAG, `查询${this.accountAlias}数据失败,错误码:${e.code},${e.message}`) } }
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。