HarmonyOS 鸿蒙Next 免密登录鸿蒙场景化代码

HarmonyOS 鸿蒙Next 免密登录鸿蒙场景化代码
<markdown _ngcontent-veo-c149="" class="markdownPreContainer">

免密登录

介绍

本示例实现了免密登录功能。

免密登录源码链接

使用说明

注意,设备需设置锁屏密码后才可使用免密登录功能。

输入账号和密码,勾选“记住密码”,底部会出现提示弹窗,点击“登录”按钮后,点击“重新加载该页面”,会出现输入锁屏密码的弹窗,输入成功,应用自动填充账号和密码。

实现效果

实现思路

保存账户信息

通过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
  }
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

查询账户信息

查询账户信息需要通过用户认证,分为以下两个步骤进行。

  1. 调用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}`)
     }
      }
    <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
  2. 调用用户认证接口,认证通过调用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()
      }
    <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
    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}`)
     }
      }
    <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

工程结构&模块类型

entry/src/main/ets/
|---entryability
|   |---EntryAbility.ets
|---pages
|   |---Index.ets              // 登录页面
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

相关权限

  1. ohos.permission.ACCESS_BIOMETRIC 用户认证权限

参考资料

关键资产存储服务

</markdown>

更多关于HarmonyOS 鸿蒙Next 免密登录鸿蒙场景化代码的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS 鸿蒙Next 免密登录鸿蒙场景化代码的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


HarmonyOS 鸿蒙Next免密登录鸿蒙场景化代码实现,通常涉及使用系统提供的API来实现设备间的信任认证,从而允许用户在特定场景下无需密码即可登录。以下是一个简化示例,展示了如何通过鸿蒙API实现设备间的免密登录功能:

#include <ohos/aafwk/ability/Ability.h>
#include <ohos/security/auth/AccountAuthManager.h>
#include <ohos/security/auth/AccountAuthCallback.h>

using namespace OHOS::AAFwk;
using namespace OHOS::Security::Auth;

class MyAbility : public Ability {
public:
    void onStart(const Intent &intent) override {
        // 获取AccountAuthManager实例
        auto accountAuthManager = AccountAuthManager::GetInstance();
        
        // 配置免密登录参数
        auto request = AccountAuthRequest::New();
        request->SetAccountId("user_account_id");
        request->SetAuthTokenType(AccountType::DEVICE);

        // 发起免密登录请求
        accountAuthManager->AuthorizeAccount(request, shared_ptr<AccountAuthCallback>(new MyAuthCallback()));
    }

private:
    class MyAuthCallback : public AccountAuthCallback {
    public:
        void OnAuthSuccess(const AccountAuthResult &result) override {
            // 处理免密登录成功结果
        }
        void OnAuthFailed(int errorCode, const string &errorMsg) override {
            // 处理免密登录失败情况
        }
    };
};

上述代码展示了如何通过AccountAuthManager进行免密登录的简化流程。如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部