背景
华为云服务提供了统一认证的云服务,支持手机、邮箱等自定义登录服务,并且提供了免费使用的额度,这样子方便中小企业或者项目快速的开发工作。下面是支持的认证方式:

操作步骤
1.AGC(AppGallery Connect)创建项目
在AGC界面创建自己的云服务项目(详细可看上篇文章 【HarmonyOS】端云一体化初始化项目),并开通认证服务,如下图:

启用手机号码和邮箱地址服务:

2.添加项目配置文件
在AGC的项目界面下载agconnect-services.json文件,并添加到本地的项目文件中。


3.添加与云服务相关的第三方库
- 在项目的终端中,输入 cd entry 进入entry目录
- 安装SDK
可以在entry->oh-package.json5文件中可以查看添加的第三方库和对应的版本号,可以看到添加了 @hw-agconnect/hmcore和 @hw-agconnect/cloud两个第三方库。

示例使用手机验证码实现登录功能
验证码的操作示意图

1.搭建初始化界面

import { router } from '@kit.ArkUI';
@Entry
@Component
struct Index {
//手机号码
@State TelNumber: string = "";
//验证码
@State VerifyNumber: string = "";
build() {
Column() {
TextInput({ placeholder: "请输入手机号" })
.width("80%")
.type(InputType.PhoneNumber)
.height(50)
.onChange(value => {
this.TelNumber = value;
})
Row() {
TextInput({ placeholder: "请输入验证码" })
.width("50%")
.type(InputType.Number)
.height(50)
.onChange(value => {
this.VerifyNumber = value;
})
Button("获取验证码")
.fontSize(14)
.layoutWeight(1)
.margin({ left: 20 })
.height(50)
}
.width("80%")
.margin({ top: 20, bottom: 20 })
Button("登录").onClick((event: ClickEvent) => {
})
.width("80%")
}
.height('100%')
.width('100%')
.padding(10)
.backgroundColor($r('app.color.start_window_background'))
.alignItems(HorizontalAlign.Center)
}
}- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
2.云服务认证使用初始化
修改EntryAbility文件代码进行初始化
- 添加import { initialize } from '@hw-agconnect/hmcore'
- 添加配置的JSON文件路径 :import serciceJson from '../../resources/rawfile/agconnect-services.json'
- 在OnCreate方法中添加初始化代码
修改示意图:

整体代码如下:
import { abilityAccessCtrl, AbilityConstant, PermissionRequestResult, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
import { initialize } from '@hw-agconnect/hmcore'
import serciceJson from '../../resources/rawfile/agconnect-services.json'
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
try {
initialize(this.context, serciceJson);
} catch (e) {
hilog.error(0x0000, 'AGConnectError', JSON.stringify(e));
}
let AtManager = abilityAccessCtrl.createAtManager();
AtManager.requestPermissionsFromUser(this.context, ['ohos.permission.READ_MEDIA', 'ohos.permission.MEDIA_LOCATION'])
.then((data: PermissionRequestResult) => {
hilog.info(0x0000, 'testTag', '%{public}s', 'request permissions from user success' + data);
})
.catch((err: Object) => {
hilog.error(0x0000, 'testTag', 'Failed to request permissions from user. Cause: %{public}s',
JSON.stringify(err) ?? '');
});
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
onDestroy(): void {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage): void {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy(): void {
// Main window is destroyed, release UI related resources
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground(): void {
// Ability has brought to foreground
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground(): void {
// Ability has back to background
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
}
}- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
发送验证码
输入手机号码后点击获取验证码按钮,然后获取登录的验证码短信。短信截图如下:

完整代码:
import { router } from '@kit.ArkUI';
import cloud from '@hw-agconnect/cloud'
import { Auth, VerifyCodeAction } from '@hw-agconnect/cloud';
import hilog from '@ohos.hilog';
import json from '@ohos.util.json';
import { JSON } from '@kit.ArkTS';
@Entry
@Component
struct Index {
//手机号码
@State TelNumber: string = "";
//验证码
@State VerifyNumber: string = "";
build() {
Column() {
TextInput({ placeholder: "请输入手机号" })
.width("80%")
.type(InputType.PhoneNumber)
.height(50)
.onChange(value => {
this.TelNumber = value;
})
Row() {
TextInput({ placeholder: "请输入验证码" })
.width("50%")
.type(InputType.Number)
.height(50)
.onChange(value => {
this.VerifyNumber = value;
})
Button("获取验证码")
.fontSize(14)
.layoutWeight(1)
.margin({ left: 20 })
.height(50)
.onClick(async () => {
try {
await cloud.auth().requestVerifyCode({
verifyCodeType: {
kind: "phone",
phoneNumber: this.TelNumber,
countryCode: "86"
},
action: VerifyCodeAction.REGISTER_LOGIN,
lang: "zh_CN",
sendInterval: 60
})
hilog.error(0, 'VerifyCode', "Success");
} catch (e) {
AlertDialog.show({ title: "错误", message: "验证码发送失败" })
hilog.error(0, 'VerifyCode', JSON.stringify(e));
}
})
}
.width("80%")
.margin({ top: 20, bottom: 20 })
Button("登录").onClick((event: ClickEvent) => {
})
.width("80%")
}
.height('100%')
.width('100%')
.padding(10)
.backgroundColor($r('app.color.start_window_background'))
.alignItems(HorizontalAlign.Center)
}
}- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
主要调用requestVerifyCode方法去获取验证码信息,传入VerifyCodeParam类型对象。
VerifyCodeParam的属性解析:
- verifyCodeType :PhoneVerifyCode对象,主要输入phoneNumber和countryCode对象。
- action : 枚举值,选择获取验证码的类型
- lang : 语言
- sendInterval : 重复发送的时间间隔
根据验证码实现登录功能
实现登录效果

import { router } from '@kit.ArkUI';
import cloud from '@hw-agconnect/cloud'
import { Auth, VerifyCodeAction } from '@hw-agconnect/cloud';
import hilog from '@ohos.hilog';
import json from '@ohos.util.json';
import { JSON } from '@kit.ArkTS';
@Entry
@Component
struct Index {
//手机号码
@State TelNumber: string = "";
//验证码
@State VerifyNumber: string = "";
build() {
Column() {
TextInput({ placeholder: "请输入手机号" })
.width("80%")
.type(InputType.PhoneNumber)
.height(50)
.onChange(value => {
this.TelNumber = value;
})
Row() {
TextInput({ placeholder: "请输入验证码" })
.width("50%")
.type(InputType.Number)
.height(50)
.onChange(value => {
this.VerifyNumber = value;
})
Button("获取验证码")
.fontSize(14)
.layoutWeight(1)
.margin({ left: 20 })
.height(50)
.onClick(async () => {
try {
await cloud.auth().requestVerifyCode({
verifyCodeType: {
kind: "phone",
phoneNumber: this.TelNumber,
countryCode: "86"
},
action: VerifyCodeAction.REGISTER_LOGIN,
lang: "zh_CN",
sendInterval: 60
})
hilog.error(0, 'VerifyCode', "Success");
} catch (e) {
AlertDialog.show({ title: "错误", message: "验证码发送失败" })
hilog.error(0, 'VerifyCode', JSON.stringify(e));
}
})
}
.width("80%")
.margin({ top: 20, bottom: 20 })
Button("登录").onClick(async (event: ClickEvent) => {
try {
const result = await cloud.auth().signIn({
credentialInfo: {
kind: "phone",
countryCode: "86",
phoneNumber: this.TelNumber,
verifyCode: this.VerifyNumber
}
})
AlertDialog.show({ title: "登录", message: "登录成功!!!" })
} catch (e) {
AlertDialog.show({ title: "错误", message: "登录失败" })
hilog.error(0, 'Login', JSON.stringify(e));
}
})
.width("80%")
}
.height('100%')
.width('100%')
.padding(10)
.backgroundColor($r('app.color.start_window_background'))
.alignItems(HorizontalAlign.Center)
}
}- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
主要调用auth的signIn方法,并传入对应的电话号码和验证码。 SignInParam对象
- credentialInfo: CredentialInfo对象,设置电话号码和前缀,可以选择密码登录或者验证码登录
- autoCreateUser?: boolean; 设置当没有当前对象存在时,是否需要自动生成用户。
总结
以上示例仅仅对统一认证流程的讲解,其中完整的逻辑判断并没有添加,可以根据自己的需求来添加相应的逻辑判断
浙公网安备 33010602011771号