HarmonyOS 鸿蒙Next 用户注册与登录功能实现——玩具店购物应用开发实战(二)

HarmonyOS 鸿蒙Next 用户注册与登录功能实现——玩具店购物应用开发实战(二)

用户注册与登录功能实现——玩具店购物应用开发实战(二)

在上一篇文章中,我们完成了玩具店购物应用的项目规划与环境搭建。本篇文章将详细介绍用户注册登录功能的实现,包括用户输入验证、密码加密、登录状态管理等。

一、功能概述

1. 功能需求

  • 用户注册

    • 用户可以通过邮箱和密码注册新账号。
    • 注册时需要对输入的信息进行验证,如邮箱格式、密码强度等。
    • 注册成功后,自动登录并跳转到商品列表页。
  • 用户登录

    • 已注册用户可以通过邮箱和密码登录。
    • 登录时需要验证用户输入的邮箱和密码是否正确。
    • 登录成功后,保存登录状态,方便下次自动登录。
  • 用户注销

    • 用户可以退出登录状态,清除本地的登录信息。

2. 技术难点

  • 输入验证:如何有效地验证用户输入的信息,确保数据的有效性和安全性。
  • 密码加密:如何对用户的密码进行加密存储,防止明文存储导致的安全问题。
  • 登录状态管理:如何在应用中保存和管理用户的登录状态,实现自动登录。

二、数据库设计与实现

在第一篇文章中,我们已经设计了users表,用于存储用户信息。现在,我们需要完善数据库的初始化和连接。

1. 数据库初始化

common/utils/DatabaseHelper.ets中,已经创建了DatabaseHelper类,用于数据库的初始化。现在,我们需要完善用户表的创建和密码加密。

// common/utils/DatabaseHelper.ets
import rdb from '@ohos.data.rdb';

export class DatabaseHelper {
  private static instance: rdb.RdbStore;

  static async getRdbStore(): Promise<rdb.RdbStore> {
    if (!this.instance) {
      const config = {
        name: 'ToyStore.db',
        version: 1,
        onCreate: (db: rdb.RdbStore) => {
          // 创建用户表
          db.executeSql(`
            CREATE TABLE IF NOT EXISTS users (
              id INTEGER PRIMARY KEY AUTOINCREMENT,
              email TEXT UNIQUE,
              password TEXT
            )
          `);
          // 其他表的创建...
        },
      };
      this.instance = await rdb.getRdbStore(config);
    }
    return this.instance;
  }
}

2. 密码加密存储

为了保证用户密码的安全性,我们需要对密码进行加密存储。这里我们使用SHA-256算法进行哈希处理。

创建加密工具类

common/utils目录下,创建CryptoHelper.ets,用于密码的加密。

// common/utils/CryptoHelper.ets
import crypto from '@ohos.cryptographic';

export class CryptoHelper {
  static hashPassword(password: string): string {
    const messageDigest = crypto.createMessageDigest('SHA-256');
    messageDigest.update(new Uint8Array(crypto.stringToUint8Array(password)));
    const hash = messageDigest.digest();
    return crypto.uint8ArrayToHex(hash);
  }
}

三、用户注册功能实现

1. 注册页面布局

pages/RegisterPage.ets中,创建注册页面的UI布局。

// pages/RegisterPage.ets
@Entry
@Component
struct RegisterPage {
  @State email: string = '';
  @State password: string = '';
  @State confirmPassword: string = '';

  build() {
    Column({ space: 16 }) {
      Text('用户注册').fontSize(24).margin({ top: 32 });
      TextField({ placeholder: '邮箱', text: this.email })
        .onChange(value => this.email = value)
        .type(TextInputType.EmailAddress);
      TextField({ placeholder: '密码', text: this.password })
        .onChange(value => this.password = value)
        .type(TextInputType.Password);
      TextField({ placeholder: '确认密码', text: this.confirmPassword })
        .onChange(value => this.confirmPassword = value)
        .type(TextInputType.Password);
      Button('注册')
        .onClick(() => this.register())
        .margin({ top: 16 });
      Button('已有账号?登录')
        .onClick(() => Router.replace({ uri: 'LoginPage' }))
        .type(ButtonType.Normal);
    }.padding(16);
  }

  async register() {
    // 输入验证
    if (!this.email || !this.password || !this.confirmPassword) {
      prompt.showToast({ message: '请填写完整信息' });
      return;
    }
    if (!this.validateEmail(this.email)) {
      prompt.showToast({ message: '邮箱格式不正确' });
      return;
    }
    if (this.password !== this.confirmPassword) {
      prompt.showToast({ message: '两次密码输入不一致' });
      return;
    }
    if (this.password.length < 6) {
      prompt.showToast({ message: '密码长度至少为6位' });
      return;
    }

    // 检查邮箱是否已注册
    const query = 'SELECT * FROM users WHERE email = ?';
    const resultSet = await this.store.query(query, [this.email]);
    if (resultSet.goToFirstRow()) {
      prompt.showToast({ message: '邮箱已注册' });
      resultSet.close();
      return;
    }
    resultSet.close();

    // 密码加密
    const hashedPassword = CryptoHelper.hashPassword(this.password);

    // 插入新用户
    const values = {
      'email': this.email,
      'password': hashedPassword,
    };
    await this.store.insert('users', values);
    prompt.showToast({ message: '注册成功' });

    // 自动登录,保存登录状态
    AppStorage.SetOrCreate('isLoggedIn', true);
    AppStorage.SetOrCreate('userEmail', this.email);

    // 跳转到商品列表页
    Router.replace({ uri: 'ProductListPage' });
  }

  validateEmail(email: string): boolean {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(email);
  }
}

2. 输入验证

register()方法中,添加对用户输入的验证。

import prompt from '@ohos.prompt';
import { DatabaseHelper } from '../common/utils/DatabaseHelper';
import { CryptoHelper } from '../common/utils/CryptoHelper';

@Component
struct RegisterPage {
  // 前面的代码

  private store: rdb.RdbStore;

  aboutToAppear() {
    this.initDatabase();
  }

  async initDatabase() {
    this.store = await DatabaseHelper.getRdbStore();
  }

  async register() {
    // 输入验证
    if (!this.email || !this.password || !this.confirmPassword) {
      prompt.showToast({ message: '请填写完整信息' });
      return;
    }
    if (!this.validateEmail(this.email)) {
      prompt.showToast({ message: '邮箱格式不正确' });
      return;
    }
    if (this.password !== this.confirmPassword) {
      prompt.showToast({ message: '两次密码输入不一致' });
      return;
    }
    if (this.password.length < 6) {
      prompt.showToast({ message: '密码长度至少为6位' });
      return;
    }

    // 检查邮箱是否已注册
    const query = 'SELECT * FROM users WHERE email = ?';
    const resultSet = await this.store.query(query, [this.email]);
    if (resultSet.goToFirstRow()) {
      prompt.showToast({ message: '邮箱已注册' });
      resultSet.close();
      return;
    }
    resultSet.close();

    // 密码加密
    const hashedPassword = CryptoHelper.hashPassword(this.password);

    // 插入新用户
    const values = {
      'email': this.email,
      'password': hashedPassword,
    };
    await this.store.insert('users', values);
    prompt.showToast({ message: '注册成功' });

    // 自动登录,保存登录状态
    AppStorage.SetOrCreate('isLoggedIn', true);
    AppStorage.SetOrCreate('userEmail', this.email);

    // 跳转到商品列表页
    Router.replace({ uri: 'ProductListPage' });
  }

  validateEmail(email: string): boolean {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(email);
  }
}

3. 解释

  • 输入验证:检查邮箱格式、密码长度、两次密码是否一致等。
  • 邮箱唯一性:在数据库中查询是否已有相同的邮箱注册。
  • 密码加密:使用CryptoHelper.hashPassword()对密码进行哈希处理。
  • 保存登录状态:使用AppStorage保存登录状态和用户邮箱。
  • 页面跳转:注册成功后,跳转到商品列表页。

四、用户登录功能实现

1. 登录页面布局

pages/LoginPage.ets中,创建登录页面的UI布局。

// pages/LoginPage.ets
@Entry
@Component
struct LoginPage {
  @State email: string = '';
  @State password: string = '';

  build() {
    Column({ space: 16 }) {
      Text('用户登录').fontSize(24).margin({ top: 32 });
      TextField({ placeholder: '邮箱', text: this.email })
        .onChange(value => this.email = value)
        .type(TextInputType.EmailAddress);
      TextField({ placeholder: '密码', text: this.password })
        .onChange(value => this.password = value)
        .type(TextInputType.Password);
      Button('登录')
        .onClick(() => this.login())
        .margin({ top: 16 });
      Button('没有账号?注册')
        .onClick(() => Router.replace({ uri: 'RegisterPage' }))
        .type(ButtonType.Normal);
    }.padding(16);
  }

  async login() {
    if (!this.email || !this.password) {
      prompt.showToast({ message: '请输入邮箱和密码' });
      return;
    }

    // 密码加密
    const hashedPassword = CryptoHelper.hashPassword(this.password);

    // 查询用户
    const query = 'SELECT * FROM users WHERE email = ? AND password = ?';
    const resultSet = await this.store.query(query, [this.email, hashedPassword]);
    if (resultSet.goToFirstRow()) {
      prompt.showToast({ message: '登录成功' });

      // 保存登录状态
      AppStorage.SetOrCreate('isLoggedIn', true);
      AppStorage.SetOrCreate('userEmail', this.email);

      // 跳转到商品列表页
      Router.replace({ uri: 'ProductListPage' });
    } else {
      prompt.showToast({ message: '邮箱或密码错误' });
    }
    resultSet.close();
  }
}

2. 登录逻辑实现

import prompt from '@ohos.prompt';
import { DatabaseHelper } from '../common/utils/DatabaseHelper';
import { CryptoHelper } from '../common/utils/CryptoHelper';

@Component
struct LoginPage {
  // 前面的代码

  private store: rdb.RdbStore;

  aboutToAppear() {
    this.initDatabase();
  }

  async initDatabase() {
    this.store = await DatabaseHelper.getRdbStore();
  }

  async login() {
    if (!this.email || !this.password) {
      prompt.showToast({ message: '请输入邮箱和密码' });
      return;
    }

    // 密码加密
    const hashedPassword = CryptoHelper.hashPassword(this.password);

    // 查询用户
    const query = 'SELECT * FROM users WHERE email = ? AND password = ?';
    const resultSet = await this.store.query(query, [this.email, hashedPassword]);
    if (resultSet.goToFirstRow()) {
      prompt.showToast({ message: '登录成功' });

      // 保存登录状态
      AppStorage.SetOrCreate('isLoggedIn', true);
      AppStorage.SetOrCreate('userEmail', this.email);

      // 跳转到商品列表页
      Router.replace({ uri: 'ProductListPage' });
    } else {
      prompt.showToast({ message: '邮箱或密码错误' });
    }
    resultSet.close();
  }
}

3. 解释

  • 密码加密对比:将用户输入的密码进行哈希处理,与数据库中的加密密码进行比较。
  • 保存登录状态:登录成功后,使用AppStorage保存登录状态。
  • 错误提示:登录失败时,给出友好的提示信息。

五、登录状态管理

1. 自动登录实现

app.ets中,应用启动时检查登录状态,决定跳转的页面。

// app.ets
import router from '@ohos.router';

@Entry
@Component
struct App {
  build() {
    // 检查登录状态
    if (AppStorage.Get('isLoggedIn')) {
      router.replace({ uri: 'ProductListPage' });
    } else {
      router.replace({ uri: 'LoginPage' });
    }
  }
}

2. 用户注销功能

在商品列表页或个人中心页,添加“注销”按钮,用户可以退出登录。

// 在商品列表页或其他页面添加注销功能
Button('注销')
  .onClick(() => this.logout())
  .margin({ top: 16 });

logout() {
  // 清除登录状态
  AppStorage.Set('isLoggedIn', false);
  AppStorage.Delete('userEmail');
  prompt.showToast({ message: '已退出登录' });
  Router.replace({ uri: 'LoginPage' });
}

六、完善用户体验

1. 异常处理

  • 数据库异常:在数据库操作中,添加try...catch,捕获异常并提示用户。
  • 网络异常:如果有网络请求,需处理网络不可用或超时的情况。

2. 输入提示

  • 在用户输入不符合要求时,使用prompt.showToast()给出明确的提示信息,指导用户正确输入。

3. 界面优化

  • 布局美化:使用合理的间距、字体大小和颜色,提升界面美观度。
  • 按钮样式:自定义按钮的样式,使其更加符合应用的风格。

七、测试与调试

1. 测试用例

  • 注册流程测试

    • 输入有效的邮箱和密码,注册成功。
    • 输入已注册的邮箱,提示邮箱已注册。
    • 输入不匹配的密码和确认密码,提示错误。
  • 登录流程测试

    • 输入正确的邮箱和密码,登录成功。
    • 输入错误的邮箱或密码,提示登录失败。
  • 自动登录测试

    • 登录成功后,关闭应用再打开,自动跳转到商品列表页。
  • 注销功能测试

    • 点击注销按钮,成功退出登录,回到登录页。

2. 调试方法

  • 日志输出:使用console.log()console.error()输出调试信息。
  • 断点调试:在DevEco Studio中设置断点,逐步检查代码执行流程。
  • 查看数据库:在开发过程中,可以使用数据库浏览工具查看数据库内容,验证数据是否正确写入。

目前我们实现了玩具店购物应用的用户注册登录功能。通过对用户输入的验证、密码的加密存储以及登录状态的管理,确保了用户数据的安全性和应用的易用性。在下一篇文章中,我们将实现商品列表商品详情展示,包括从数据库或网络加载商品数据、商品的搜索和筛选等功能。


更多关于HarmonyOS 鸿蒙Next 用户注册与登录功能实现——玩具店购物应用开发实战(二)的实战教程也可以访问 https://www.itying.com/category-93-b0.html

1 回复

更多关于HarmonyOS 鸿蒙Next 用户注册与登录功能实现——玩具店购物应用开发实战(二)的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


针对帖子标题“HarmonyOS 鸿蒙Next 用户注册与登录功能实现——玩具店购物应用开发实战(二)”的问题,以下是关于鸿蒙系统中实现用户注册与登录功能的专业回答:

在鸿蒙系统中实现用户注册与登录功能,通常涉及以下几个关键步骤:

  1. 界面设计:首先,需要在鸿蒙的ArkUI框架中设计用户注册与登录的界面。这包括输入框、按钮等UI组件,确保用户能够方便地输入账号、密码等信息。

  2. 数据存储:为了实现用户信息的持久化存储,可以使用鸿蒙提供的分布式数据管理功能,或者通过SQLite等数据库来存储用户数据。

  3. 网络请求:在用户点击注册或登录按钮时,应用需要向服务器发送请求。鸿蒙系统支持多种网络请求方式,如Fetch API等,可用于实现与后端的通信。

  4. 安全性考虑:在实现过程中,需要注意保护用户数据的安全性,如使用HTTPS协议进行通信,对密码进行加密处理等。

  5. 错误处理:对用户输入的错误、网络请求失败等情况进行妥善处理,提高应用的用户体验。

通过上述步骤,可以在鸿蒙系统中实现用户注册与登录的基本功能。如果在实现过程中遇到问题,可以参考鸿蒙系统的官方文档或开发者社区的资源。如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html。

回到顶部