HarmonyOS 鸿蒙Next《仿盒马》app开发技术分享设置安全锁

HarmonyOS 鸿蒙Next《仿盒马》app开发技术分享设置安全锁

技术栈

Appgallery connect

开发准备

上一节我们实现了提现页面以及部分组件的业务逻辑,那么我们在提现这一步为了更多的安全层面的考虑,设置了一个安全锁,用户只要开启了安全锁,那么每次的提现,都需要把本地的密码提交到云端核对安全锁的内容才可以执行后续的提现步骤,如果不能解锁,那么后续的内容都无法实现,这更好的保护了用户的财产安全

功能分析

要实现这个功能首先我们需要在个人页面添加一个安全入口,然后在安全锁设置页面开启安全锁的按钮,当没有开启安全锁的时候,点击开启按钮会出现一个安全锁的弹窗,在弹窗里设置对应的密码,设置成功后保存对应的内容提交到云端,进行保存,方便后续的校验,关闭安全锁则在云端删除对应的内容

代码实现

首先我们直接在个人页面的列表中添加上对应的数据

 new SectionLine("安全",
    "设置安全锁",
    $r('app.media.anquan'),
    false),

然后给这条数据添加对应的点击事件

if (item.title=='安全'){
    if (this.user!=null) {
        router.pushUrl({url:'pages/view/LockPage'})
    }else {
        showToast("请先登录")
    }
}

接下来创建安全锁对应的表

{
    "objectTypeName": "verify_info",
    "fields": [
        {"fieldName": "id", "fieldType": "Integer", "notNull": true, "belongPrimaryKey": true},
        {"fieldName": "open_lock", "fieldType": "Boolean"},
        {"fieldName": "lock_str", "fieldType": "String"},
        {"fieldName": "user_id", "fieldType": "Integer"}
    ],
    "indexes": [
        {"indexName": "field1Index", "indexList": [{"fieldName":"id","sortType":"ASC"}]}
    ],
    "permissions": [
        {"role": "World", "rights": ["Read", "Upsert", "Delete"]},
        {"role": "Authenticated", "rights": ["Read", "Upsert", "Delete"]},
        {"role": "Creator", "rights": ["Read", "Upsert", "Delete"]},
        {"role": "Administrator", "rights": ["Read", "Upsert", "Delete"]}
    ]
}

创建对应的安全锁页面,在页面中设置好对应的参数

@State user: User|null=null
@State flag:boolean=false
@State lockInfo:VerifyInfo|null=null
@State lock_ui_visibility:boolean=false
Column({space:10}) {
    CommonTopBar({ title: "安全锁", alpha: 0, titleAlignment: TextAlign.Center ,backButton:true})
    Row(){
        Text("安全锁")
            .fontColor(Color.Black)
            .fontSize(16)
        Image(this.lock_ui_visibility?$r('app.media.kai'):$r('app.media.guan'))
            .width(60)
            .height(30)
            .onClick(()=>{})
    }
    .width('100%')
    .justifyContent(FlexAlign.SpaceBetween)
    .padding({left:10,right:10})
    Divider().width('100%').height(0.8)
        .color("#e6e6e6")
    .width('100%')
}.width('100%').height('100%').backgroundColor(Color.White)

接下来我们创建对应的安全锁设置弹窗并整理好对应的逻辑

import { LengthUnit } from '@kit.ArkUI';
@Preview
@CustomDialog
export struct LockDialog {
    @State passwords: Number[]=[];
    @Link lock_ui_visibility:boolean
    @State message: string = '绘制您的密码图案!';
    public callback:(passwords:string)=>void=():void=>{}
    private patternLockController: PatternLockController = new PatternLockController();
    controller: CustomDialogController;
    build() {
        Column({space:20}) {
            Text(this.message).textAlign(TextAlign.Center).margin(20).fontSize(20)
                .fontColor(Color.Black)
            PatternLock(this.patternLockController)
                .sideLength(300)
                .circleRadius(9)
                .pathStrokeWidth(5)
                .activeColor('#707070')
                .selectedColor('#707070')
                .pathColor('#707070')
                .backgroundColor('#F5F5F5')
                .autoReset(true)
                .activateCircleStyle({
                    color: '#707070',
                    radius: { value: 16, unit: LengthUnit.VP },
                    enableWaveEffect: true
                })
                .onDotConnect((index: number) => {
                    console.log("onDotConnect index: " + index);
                })
                .onPatternComplete((input: Array<number>) => {
                    if (input.length < 5) {
                        this.message = '图案连接数不能小于5';
                        return;
                    }
                    if (this.passwords.length > 0) {
                        if (this.passwords.toString() === input.toString()) {
                            this.passwords = input;
                            this.message = '图案码设置完成';
                            this.patternLockController.setChallengeResult(PatternLockChallengeResult.CORRECT);
                            const str: string = JSON.stringify(this.passwords);
                            this.callback(str)
                            this.controller.close()
                        } else {
                            this.message = '图案码核对失败,请确认后重新绘制.';
                            this.patternLockController.setChallengeResult(PatternLockChallengeResult.WRONG);
                        }
                    } else {
                        this.passwords = input;
                        this.message = "请再次绘制图案码.";
                    }
                })
        }
        .borderRadius({topLeft:20,topRight:20})
        .justifyContent(FlexAlign.Start)
        .backgroundColor(Color.White)
        .height(500)
        .width('100%')
    }
}

接下来我们在页面内调用

private dialogController: CustomDialogController = new CustomDialogController({
    builder: LockDialog({
        lock_ui_visibility:this.lock_ui_visibility,
        callback: async (str:string)=>{
            //在这里提交表单信息,成功插入之后关闭弹窗,修改安全锁按钮的状态,重新查询数据赋值lockInfo
            showToast(str)
            let info=new verify_info()
            info.id=Math.floor(Math.random() * 1000000)
            info.open_lock=true
            info.lock_str=str
            info.user_id=this.user!.user_id
            let num = await databaseZone.upsert(info);
            if (num>0) {
                this.lock_ui_visibility=true
                this.initLockInfo()
            }
        }
    }),
    alignment: DialogAlignment.Bottom,
    customStyle:false
});

因为我们提交数据需要用户信息,首次进入页面也需要加载对应的状态所以还需要进行数据查询

async initLockInfo(){
    const value = await StorageUtils.getAll('user');
    if (value != "") {
        this.user = JSON.parse(value)
    }
    let databaseZone = cloudDatabase.zone('default');
    let condition = new cloudDatabase.DatabaseQuery(verify_info);
    condition.equalTo("user_id", this.user?.user_id)
    let listData = await databaseZone.query(condition);
    let json = JSON.stringify(listData)
    let data: VerifyInfo[] = JSON.parse(json)
    if (data.length>0) {
        this.lock_ui_visibility=true
        this.lockInfo=data[0]
    }else {
        this.lock_ui_visibility=false
    }
}

在生命周期方法内调用

async aboutToAppear(): Promise<void> {
    this.initLockInfo()
}

实现开关的业务逻辑

build() {
    Column({space:10}) {
        CommonTopBar({ title: "安全锁", alpha: 0, titleAlignment: TextAlign.Center ,backButton:true})
        Row(){
            Text("安全锁")
                .fontColor(Color.Black)
                .fontSize(16)
            Image(this.lock_ui_visibility?$r('app.media.kai'):$r('app.media.guan'))
                .width(60)
                .height(30)
                .onClick(async ()=>{
                    if (this.lock_ui_visibility) {
                        let info=new verify_info()
                        info.id=this.lockInfo!.id
                        let num = await databaseZone.delete(info);
                        if (num>0) {
                            this.lock_ui_visibility=false
                        }
                    }else {
                        this.dialogController.open()
                    }
                })
        }
        .width('100%')
        .justifyContent(FlexAlign.SpaceBetween)
        .padding({left:10,right:10})
        Divider().width('100%').height(0.8)
            .color("#e6e6e6")
        .width('100%')
    }.width('100%').height('100%').backgroundColor(Color.White)
}

更多关于HarmonyOS 鸿蒙Next《仿盒马》app开发技术分享设置安全锁的实战教程也可以访问 https://www.itying.com/category-93-b0.html

2 回复

鸿蒙Next开发安全锁功能可使用以下技术方案:

  1. 使用@ohos.userIAM.userAuth模块实现生物识别验证
  2. 通过@ohos.security.huks存储和管理加密密钥
  3. 利用Preferences数据库存储锁定状态和配置
  4. 实现锁屏界面使用自定义弹窗组件
  5. 结合Ability生命周期管理验证时机

关键代码示例:

import userAuth from '[@ohos](/user/ohos).userIAM.userAuth';

// 生物识别验证
const auth = new userAuth.UserAuth();
auth.auth(用户认证参数);

注意处理以下场景:

  • 应用切换时验证
  • 后台返回前台时触发
  • 支付等敏感操作前校验

更多关于HarmonyOS 鸿蒙Next《仿盒马》app开发技术分享设置安全锁的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


从技术实现来看,这个安全锁功能设计得比较完整,主要涉及以下几个关键点:

  1. 数据库设计方面:
  • 创建了verify_info表存储安全锁状态和密码
  • 使用user_id关联用户,确保数据隔离
  • 设置了合理的字段类型和索引
  1. 功能实现亮点:
  • 使用PatternLock组件实现手势密码输入
  • 通过CustomDialog封装密码设置流程
  • 密码需连接5个点以上才有效,提高了安全性
  • 采用二次确认模式防止误操作
  1. 数据交互:
  • 使用cloudDatabase进行云端数据存储
  • 通过StorageUtils管理本地用户数据
  • 完整的增删改查操作确保数据一致性
  1. 状态管理:
  • 使用@State管理组件状态
  • 通过lock_ui_visibility控制UI显示
  • 生命周期函数初始化数据

建议可以进一步完善:

  1. 密码传输建议加密处理
  2. 可增加密码错误次数限制
  3. 考虑添加生物识别作为备选验证方式

整体实现符合HarmonyOS开发规范,代码结构清晰,是一个典型的安全功能实现方案。

回到顶部