找回密码
 立即注册
首页 业界区 业界 开发者工具箱-华为账号登录功能实现

开发者工具箱-华为账号登录功能实现

奸轲嫣 2025-6-21 02:24:13
华为账号登录功能实现

最近项目要接入华为账号登录,SDK文档看着还行,真用起来发现坑还不少。这里把踩过的坑和实现细节都记下来,省得以后自己或者同事再掉坑里。
一、基础知识

1.1 什么是华为账号登录

华为账号登录就是让用户用华为账号一键登录你App,省去注册、记密码的麻烦。用过微信/QQ登录的都懂,套路差不多。
1.2 主要概念


  • UnionID:全局唯一,跨App识别同一用户。别搞混了,和OpenID不是一回事。
  • OpenID:单App唯一,换个App就变了。
  • AuthorizationCode:临时凭证,后端用来换token。
  • AccessToken:拿这个去调接口,别暴露给前端。
二、开发背景

我们项目用户大多用华为手机,老板一句"加个华为账号登录吧",于是就有了这篇笔记。SDK集成其实不难,难的是各种边界和异常场景。
三、实现步骤

3.1 基础配置
  1. // 该引的都得引,不然编译直接报错
  2. import { LoginWithHuaweiIDButton, loginComponentManager, authentication } from '@kit.AccountKit';
  3. import { BusinessError } from '@kit.BasicServicesKit';
  4. import { hilog } from '@kit.PerformanceAnalysisKit';
  5. import { util } from '@kit.ArkTS';
  6. import { RDBUtils } from '../../utils/rdbutils';
  7. import { UserInfo } from '../../utils/rdbutils';
  8. import dataPreferences from '@ohos.data.preferences';
  9. import common from '@ohos.app.ability.common';
  10. import promptAction from '@ohos.promptAction';
  11. import router from '@ohos.router';
复制代码
3.2 登录功能实现
  1. @Entry
  2. @Component
  3. struct PreviewLoginButtonPage {
  4.   // 数据库工具实例
  5.   private rdbUtils: RDBUtils = RDBUtils.getInstance(getContext(this));
  6.   private context: common.Context = getContext(this);
  7.   
  8.   // 状态变量
  9.   @State userInfo: UserInfo | null = null;
  10.   @State isLoggedIn: boolean = false;
  11.   @State showUserInfo: boolean = false;
  12.   @State loading: boolean = false;
  13.   // 登录按钮控制器
  14.   controller: loginComponentManager.LoginWithHuaweiIDButtonController =
  15.     new loginComponentManager.LoginWithHuaweiIDButtonController()
  16.       .onClickLoginWithHuaweiIDButton(async (error: BusinessError, response: loginComponentManager.HuaweiIDCredential) => {
  17.         if (error) {
  18.           hilog.error(0x0000, 'testTag',
  19.             `登录失败. 错误码: ${error.code}, 错误信息: ${error.message}`);
  20.           return;
  21.         }
  22.         if (response) {
  23.           this.loading = true;
  24.           try {
  25.             // 获取登录凭证
  26.             const authCode = response.authorizationCode;
  27.             const openID = response.openID;
  28.             const unionID = response.unionID;
  29.             const idToken = response.idToken;
  30.             // 获取用户详细信息
  31.             const authRequest = new authentication.HuaweiIDProvider()
  32.               .createAuthorizationWithHuaweiIDRequest();
  33.             authRequest.scopes = ['profile'];
  34.             authRequest.permissions = ['serviceauthcode'];
  35.             authRequest.forceAuthorization = true;
  36.             authRequest.state = util.generateRandomUUID();
  37.             
  38.             const controller = new authentication.AuthenticationController(this.context);
  39.             const data = await controller.executeRequest(authRequest);
  40.             
  41.             // 处理用户信息
  42.             const userInfo: UserInfo = {
  43.               avatarUri: data.data?.avatarUri || '',
  44.               nickName: data.data?.nickName || '',
  45.               unionID: data.data?.unionID || '',
  46.               openID: data.data?.openID || '',
  47.               authorizationCode: data.data?.authorizationCode || '',
  48.               createTime: Date.now(),
  49.               memo: '华为账号登录'
  50.             };
  51.             // 保存用户信息
  52.             await this.saveUserInfo(userInfo);
  53.             
  54.             // 更新状态
  55.             this.isLoggedIn = true;
  56.             this.showUserInfo = true;
  57.           } catch (err) {
  58.             hilog.error(0x0000, 'testTag', `登录处理失败: ${err}`);
  59.           } finally {
  60.             this.loading = false;
  61.           }
  62.         }
  63.       });
  64. }
复制代码
3.3 用户信息管理
  1. private async saveUserInfo(userInfo: UserInfo) {
  2.   try {
  3.     // 查询是否已存在该用户
  4.     const existingUser = await this.rdbUtils.queryUserByUnionID(userInfo.unionID);
  5.     if (existingUser) {
  6.       // 更新现有用户信息
  7.       userInfo.id = existingUser.id;
  8.       await this.rdbUtils.updateUser(userInfo);
  9.     } else {
  10.       // 插入新用户信息
  11.       await this.rdbUtils.insertUser(userInfo);
  12.     }
  13.     // 保存当前用户的unionID
  14.     await this.saveCurrentUserUnionID(userInfo.unionID);
  15.     // 显示登录成功提示
  16.     promptAction.showToast({
  17.       message: '登录成功',
  18.       duration: 2000
  19.     });
  20.     // 延迟返回首页
  21.     setTimeout(() => {
  22.       router.back();
  23.     }, 2000);
  24.   } catch (error) {
  25.     hilog.error(0x0000, 'testTag', `保存用户信息失败: ${error}`);
  26.     promptAction.showToast({
  27.       message: '登录失败',
  28.       duration: 2000
  29.     });
  30.   }
  31. }
复制代码
四、踩坑记录


  • 登录状态没持久化,用户一重启App就得重新登录,被吐槽了好几次。
  • 登录回调里没处理好异常,偶尔UI直接卡死。
  • 多设备登录状态不同步,用户切换设备后信息乱套。
  • 网络慢的时候,登录按钮没loading,用户以为点没反应。
  • 错误码处理不全,有些报错用户根本看不懂。
  • 图片没缓存,头像每次都要重新拉,体验很差。
五、使用示例
  1. // 1. 初始化登录页面
  2. @Entry
  3. @Component
  4. struct LoginPage {
  5.   build() {
  6.     Column() {
  7.       // 登录按钮
  8.       LoginWithHuaweiIDButton({
  9.         params: {
  10.           style: loginComponentManager.Style.BUTTON_RED,
  11.           extraStyle: {
  12.             buttonStyle: new loginComponentManager.ButtonStyle()
  13.               .loadingStyle({
  14.                 show: this.loading
  15.               })
  16.           },
  17.           borderRadius: 24,
  18.           loginType: loginComponentManager.LoginType.ID,
  19.           supportDarkMode: true,
  20.           verifyPhoneNumber: true
  21.         },
  22.         controller: this.controller
  23.       })
  24.     }
  25.   }
  26. }
  27. // 2. 检查登录状态
  28. private async checkLoginStatus() {
  29.   try {
  30.     this.loading = true;
  31.     const currentUnionID = await this.getCurrentUserUnionID();
  32.     if (currentUnionID) {
  33.       const user = await this.rdbUtils.queryUserByUnionID(currentUnionID);
  34.       if (user) {
  35.         this.userInfo = user;
  36.         this.isLoggedIn = true;
  37.         this.showUserInfo = true;
  38.       }
  39.     }
  40.   } catch (error) {
  41.     hilog.error(0x0000, 'testTag', `检查登录状态失败: ${error}`);
  42.   } finally {
  43.     this.loading = false;
  44.   }
  45. }
  46. // 3. 退出登录
  47. private async logout() {
  48.   try {
  49.     await this.clearCurrentUserUnionID();
  50.     this.isLoggedIn = false;
  51.     this.showUserInfo = false;
  52.     this.userInfo = null;
  53.     promptAction.showToast({
  54.       message: '已退出登录',
  55.       duration: 2000
  56.     });
  57.   } catch (error) {
  58.     hilog.error(0x0000, 'testTag', `退出登录失败: ${error}`);
  59.   }
  60. }
复制代码
六、注意事项


  • 华为开发者联盟的配置一定要对,包名、签名、权限,错一个都不行。
  • token和敏感信息一定要加密,别直接丢本地。
  • 网络慢的时候记得加loading,别让用户等得心慌。
  • 错误提示要友好,别只弹"登录失败",最好能带点原因。
  • 多端同步要做好,别让用户切换设备后信息乱套。
  • 代码里别写死任何ID和密钥,安全第一。
七、后端实现说明

这里只是前端实现,后端你得自己搞。比如token换取、用户信息存储、权限校验、接口安全,这些都得后端配合。别想着全靠前端糊弄过去,安全问题很严重。
7.1 后端服务需求


  • 用户认证服务:校验华为账号凭证、生成和管理会话、token刷新、登录状态同步。
  • 用户信息服务:存储和管理用户信息、权限、同步、更新。
  • 安全服务:数据加密、敏感信息保护、访问控制、防止数据泄露。
7.2 后端API接口
  1. // 1. 用户认证接口
  2. POST /api/auth/login
  3. Request: {
  4.   authorizationCode: string;  // 华为账号授权码
  5.   openID: string;            // 华为账号OpenID
  6.   unionID: string;           // 华为账号UnionID
  7. }
  8. Response: {
  9.   token: string;             // 用户访问令牌
  10.   refreshToken: string;      // 刷新令牌
  11.   expiresIn: number;         // 过期时间
  12. }
  13. // 2. 用户信息接口
  14. GET /api/user/info
  15. Request: {
  16.   token: string;             // 用户访问令牌
  17. }
  18. Response: {
  19.   userInfo: {
  20.     avatarUri: string;       // 头像
  21.     nickName: string;        // 昵称
  22.     unionID: string;         // UnionID
  23.     openID: string;          // OpenID
  24.     // 其他用户信息
  25.   }
  26. }
  27. // 3. 刷新令牌接口
  28. POST /api/auth/refresh
  29. Request: {
  30.   refreshToken: string;      // 刷新令牌
  31. }
  32. Response: {
  33.   token: string;             // 新的访问令牌
  34.   expiresIn: number;         // 过期时间
  35. }
复制代码
7.3 安全考虑


  • 所有接口必须HTTPS,别用明文。
  • token、敏感数据都要加密,数据库也别裸奔。
  • SQL注入、暴力破解这些老生常谈的安全问题,别掉以轻心。
  • 登录设备管理、token过期、异常检测都要有。
7.4 部署建议


  • 服务器和数据库都要有备份,别等出事才想起来。
  • 日志、监控、告警都要配好,出问题能第一时间发现。
  • 缓存用Redis,接口别被刷爆。
  • 防火墙、限流、黑名单这些都要有。
7.5 开发建议


  • 后端框架、ORM、API文档、日志系统都建议用主流方案,别造轮子。
  • 统一错误处理,日志别省。
  • 单元测试、压力测试、自动化测试都要有。
  • 安全补丁要及时打,别等被黑了才补。
7.6 注意事项


  • 需要自行实现后端服务,前端只是"壳"。
  • 华为开发者联盟账号、API权限都要提前申请。
  • 数据安全、服务监控、应急预案都要有。
  • 重要:别把密钥、token、用户数据写死在前端!
有问题欢迎留言,大家一起踩坑一起填。方案适合大部分场景,特殊需求记得多测几遍。


  • 鸿蒙应用开发指南
欢迎体验

这个已经集成到鸿蒙开发者工具箱里了,欢迎下载体验!
鸿蒙开发者工具箱
作者:在人间耕耘
邮箱:1743914721@qq.com
版权声明:本文为博主原创文章,转载请附上原文出处链接及本声明。
本文由博客一文多发平台 OpenWrite 发布!

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册