求有代码 集成第三方登录:AGC认证服务连接微信/QQ
前言
在HarmonyOS 5应用中集成第三方登录可以显著降低用户注册门槛,提升用户体验。通过AppGallery Connect(AGC)的认证服务,开发者可以轻松实现微信、QQ等主流社交平台的第三方登录功能。本文将详细介绍如何在HarmonyOS 5应用中集成AGC认证服务,并实现微信和QQ的第三方登录功能。
第一部分:环境准备与项目配置
1.1 创建HarmonyOS 5项目
在DevEco Studio中创建新项目:
模板:Empty Ability
语言:ArkTS
API版本:HarmonyOS 5.0
包名:com.example.authdemo
配置项目基本信息:
{
"app": {
"bundleName": "com.example.authdemo",
"vendor": "example",
"versionCode": 1,
"versionName": "1.0.0"
}
}
1.2 在AGC控制台配置认证服务
登录AppGallery Connect
进入"我的项目" → 选择你的项目 → "构建" → "认证服务"
点击"立即启用",选择"微信"和"QQ"作为登录方式
配置微信和QQ的App ID和App Secret(需先在微信开放平台和QQ开放平台申请)
第二部分:集成AGC认证SDK
2.1 添加依赖
修改oh-package.json5文件:
{
"dependencies": {
"@hw-agconnect/api-ohos": "^1.8.0",
"@hw-agconnect/core-ohos": "^1.8.0",
"@hw-agconnect/auth-ohos": "^1.8.0",
"@hw-agconnect/auth-weixin-ohos": "^1.8.0",
"@hw-agconnect/auth-qq-ohos": "^1.8.0"
}
}
运行依赖安装:
ohpm install
2.2 配置AGC服务
从AGC控制台下载agconnect-services.json
放入项目entry/src/main/resources/rawfile/目录
第三部分:实现第三方登录功能
3.1 创建认证服务工具类
创建entry/src/main/ets/utils/AuthService.ets:
import { agconnect } from '@hw-agconnect/api-ohos';
import { AGCAuth, AGCAuthError, AGCSignInResult, AGCUser } from '@hw-agconnect/auth-ohos';
import { AGCWeixinAuthProvider } from '@hw-agconnect/auth-weixin-ohos';
import { AGCQQAuthProvider } from '@hw-agconnect/auth-qq-ohos';
export class AuthService {
private static instance: AuthService = new AuthService();
private auth: AGCAuth;
private constructor() {
agconnect.instance().init(globalThis.abilityContext);
this.auth = AGCAuth.getInstance();
}
public static get(): AuthService {
return this.instance;
}
// 微信登录
public async signInWithWeixin(): Promise
try {
const provider = new AGCWeixinAuthProvider();
const result: AGCSignInResult = await this.auth.signIn(provider);
return result.getUser();
} catch (error) {
if (error instanceof AGCAuthError) {
throw new Error(微信登录失败: ${error.message});
}
throw error;
}
}
// QQ登录
public async signInWithQQ(): Promise
try {
const provider = new AGCQQAuthProvider();
const result: AGCSignInResult = await this.auth.signIn(provider);
return result.getUser();
} catch (error) {
if (error instanceof AGCAuthError) {
throw new Error(QQ登录失败: ${error.message});
}
throw error;
}
}
// 获取当前用户
public async getCurrentUser(): Promise<AGCUser | null> {
try {
return await this.auth.getCurrentUser();
} catch (error) {
return null;
}
}
// 退出登录
public async signOut(): Promise
try {
await this.auth.signOut();
} catch (error) {
if (error instanceof AGCAuthError) {
throw new Error(退出登录失败: ${error.message});
}
throw error;
}
}
// 获取用户令牌
public async getToken(forceRefresh: boolean = false): Promise
try {
const user = await this.getCurrentUser();
if (!user) {
throw new Error('用户未登录');
}
return await user.getToken(forceRefresh);
} catch (error) {
if (error instanceof AGCAuthError) {
throw new Error(获取令牌失败: ${error.message});
}
throw error;
}
}
}
3.2 创建登录页面
创建entry/src/main/ets/pages/LoginPage.ets:
import { AuthService } from '../utils/AuthService';
@Entry
@Component
struct LoginPage {
@State currentUser: string = '未登录';
@State loading: boolean = false;
@State errorMessage: string = '';
onPageShow() {
this.checkLoginStatus();
}
async checkLoginStatus() {
try {
const user = await AuthService.get().getCurrentUser();
if (user) {
const displayName = user.getDisplayName() || user.getEmail() || user.getPhone() || '第三方用户';
this.currentUser = 已登录: ${displayName};
} else {
this.currentUser = '未登录';
}
} catch (error) {
this.currentUser = '未登录';
console.error('检查登录状态失败:', error);
}
}
async handleWeixinLogin() {
this.loading = true;
this.errorMessage = '';
try {
const user = await AuthService.get().signInWithWeixin();
const displayName = user.getDisplayName() || '微信用户';
this.currentUser = `已登录: ${displayName}`;
} catch (error) {
this.errorMessage = error.message;
} finally {
this.loading = false;
}
}
async handleQQLogin() {
this.loading = true;
this.errorMessage = '';
try {
const user = await AuthService.get().signInWithQQ();
const displayName = user.getDisplayName() || 'QQ用户';
this.currentUser = `已登录: ${displayName}`;
} catch (error) {
this.errorMessage = error.message;
} finally {
this.loading = false;
}
}
async handleLogout() {
this.loading = true;
this.errorMessage = '';
try {
await AuthService.get().signOut();
this.currentUser = '未登录';
} catch (error) {
this.errorMessage = error.message;
} finally {
this.loading = false;
}
}
build() {
Column() {
Text('第三方登录演示')
.fontSize(25)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 30 })
Text(this.currentUser)
.fontSize(18)
.margin({ bottom: 30 })
if (this.currentUser === '未登录') {
// 登录按钮
Column() {
Button('微信登录')
.width(200)
.height(50)
.backgroundColor('#07C160')
.fontColor(Color.White)
.margin({ bottom: 20 })
.onClick(() => this.handleWeixinLogin())
Button('QQ登录')
.width(200)
.height(50)
.backgroundColor('#12B7F5')
.fontColor(Color.White)
.onClick(() => this.handleQQLogin())
}
} else {
// 用户信息与退出按钮
Column() {
Button('获取用户令牌')
.width(200)
.height(50)
.margin({ bottom: 20 })
.onClick(async () => {
try {
const token = await AuthService.get().getToken();
promptAction.showToast({ message: `令牌: ${token.substring(0, 20)}...` });
} catch (error) {
this.errorMessage = error.message;
}
})
Button('退出登录')
.width(200)
.height(50)
.backgroundColor(Color.Red)
.fontColor(Color.White)
.onClick(() => this.handleLogout())
}
}
if (this.loading) {
Progress({})
.width(50)
.height(50)
.margin({ top: 20 })
}
if (this.errorMessage) {
Text(this.errorMessage)
.fontColor(Color.Red)
.margin({ top: 20 })
}
}
.width('100%')
.height('100%')
.padding(20)
.justifyContent(FlexAlign.Center)
}
}
第四部分:处理登录状态与用户信息
4.1 创建用户信息页面
创建entry/src/main/ets/pages/ProfilePage.ets:
import { AuthService } from '../utils/AuthService';
@Entry
@Component
struct ProfilePage {
@State userInfo: {
displayName: string,
email: string,
phone: string,
photoUrl: string,
provider: string
} | null = null;
@State loading: boolean = false;
onPageShow() {
this.loadUserInfo();
}
async loadUserInfo() {
this.loading = true;
try {
const user = await AuthService.get().getCurrentUser();
if (!user) {
router.replaceUrl({ url: 'pages/LoginPage' });
return;
}
this.userInfo = {
displayName: user.getDisplayName() || '未设置',
email: user.getEmail() || '未绑定',
phone: user.getPhone() || '未绑定',
photoUrl: user.getPhotoUrl() || $r('app.media.default_avatar'),
provider: this.getProviderName(user)
};
} catch (error) {
console.error('获取用户信息失败:', error);
} finally {
this.loading = false;
}
}
private getProviderName(user: any): string {
const providers = user.getProviderInfo() || [];
if (providers.some((p: any) => p.providerId === 'weixin')) {
return '微信';
} else if (providers.some((p: any) => p.providerId === 'qq')) {
return 'QQ';
}
return '未知';
}
async handleLogout() {
try {
await AuthService.get().signOut();
router.replaceUrl({ url: 'pages/LoginPage' });
} catch (error) {
console.error('退出登录失败:', error);
}
}
build() {
Column() {
if (this.loading) {
Progress({})
.width(50)
.height(50)
.margin({ bottom: 30 })
} else if (this.userInfo) {
Column() {
// 用户头像
Image(this.userInfo.photoUrl)
.width(100)
.height(100)
.borderRadius(50)
.margin({ bottom: 20 })
// 用户信息
Column() {
Row() {
Text('昵称:')
.width(80)
.fontWeight(FontWeight.Bold)
Text(this.userInfo.displayName)
.layoutWeight(1)
}
.margin({ bottom: 10 })
Row() {
Text('邮箱:')
.width(80)
.fontWeight(FontWeight.Bold)
Text(this.userInfo.email)
.layoutWeight(1)
}
.margin({ bottom: 10 })
Row() {
Text('手机:')
.width(80)
.fontWeight(FontWeight.Bold)
Text(this.userInfo.phone)
.layoutWeight(1)
}
.margin({ bottom: 10 })
Row() {
Text('登录方式:')
.width(80)
.fontWeight(FontWeight.Bold)
Text(this.userInfo.provider)
.layoutWeight(1)
}
}
.width('80%')
.padding(20)
.border({ width: 1, color: '#EEEEEE' })
.borderRadius(10)
.margin({ bottom: 30 })
// 退出按钮
Button('退出登录')
.width(200)
.height(50)
.backgroundColor(Color.Red)
.fontColor(Color.White)
.onClick(() => this.handleLogout())
}
}
}
.width('100%')
.height('100%')
.padding(20)
.justifyContent(FlexAlign.Center)
}
}
4.2 配置路由
在entry/src/main/resources/base/profile/main_pages.json中添加:
{
"src": [
"pages/LoginPage",
"pages/ProfilePage"
]
}
第五部分:第三方平台配置
5.1 微信开放平台配置
登录微信开放平台
创建移动应用,获取AppID和AppSecret
配置应用签名和包名(必须与AGC中配置一致)
在"接口权限"中申请"微信登录"权限
5.2 QQ开放平台配置
登录QQ开放平台
创建移动应用,获取AppID和AppKey
配置Android包名和签名(必须与AGC中配置一致)
在"权限管理"中申请"获取用户信息"权限
第六部分:高级功能实现
6.1 绑定多个第三方账号
扩展AuthService.ets:
// 添加到AuthService类
// 绑定微信账号
public async linkWeixinAccount(): Promise
try {
const user = await this.getCurrentUser();
if (!user) {
throw new Error('请先登录');
}
const provider = new AGCWeixinAuthProvider();
await user.link(provider);
} catch (error) {
if (error instanceof AGCAuthError) {
throw new Error(绑定微信失败: ${error.message});
}
throw error;
}
}
// 绑定QQ账号
public async linkQQAccount(): Promise
try {
const user = await this.getCurrentUser();
if (!user) {
throw new Error('请先登录');
}
const provider = new AGCQQAuthProvider();
await user.link(provider);
} catch (error) {
if (error instanceof AGCAuthError) {
throw new Error(绑定QQ失败: ${error.message});
}
throw error;
}
}
// 解绑第三方账号
public async unlinkProvider(providerId: string): Promise
try {
const user = await this.getCurrentUser();
if (!user) {
throw new Error('请先登录');
}
await user.unlink(providerId);
} catch (error) {
if (error instanceof AGCAuthError) {
throw new Error(解绑失败: ${error.message});
}
throw error;
}
}
6.2 创建账号绑定页面
创建entry/src/main/ets/pages/AccountLinkPage.ets:
import { AuthService } from '../utils/AuthService';
@Entry
@Component
struct AccountLinkPage {
@State providers: Array<{id: string, name: string, linked: boolean}> = [];
@State loading: boolean = false;
@State message: string = '';
onPageShow() {
this.loadProviderInfo();
}
async loadProviderInfo() {
this.loading = true;
try {
const user = await AuthService.get().getCurrentUser();
if (!user) {
router.replaceUrl({ url: 'pages/LoginPage' });
return;
}
const providerInfo = user.getProviderInfo() || [];
this.providers = [
{ id: 'weixin', name: '微信', linked: providerInfo.some(p => p.providerId === 'weixin') },
{ id: 'qq', name: 'QQ', linked: providerInfo.some(p => p.providerId === 'qq') }
];
} catch (error) {
console.error('获取账号绑定信息失败:', error);
} finally {
this.loading = false;
}
}
async handleLink(providerId: string) {
this.loading = true;
this.message = '';
try {
if (providerId === 'weixin') {
await AuthService.get().linkWeixinAccount();
} else if (providerId === 'qq') {
await AuthService.get().linkQQAccount();
}
this.message = '绑定成功';
await this.loadProviderInfo();
} catch (error) {
this.message = error.message;
} finally {
this.loading = false;
}
}
async handleUnlink(providerId: string) {
this.loading = true;
this.message = '';
try {
await AuthService.get().unlinkProvider(providerId);
this.message = '解绑成功';
await this.loadProviderInfo();
} catch (error) {
this.message = error.message;
} finally {
this.loading = false;
}
}
build() {
Column() {
Text('账号绑定管理')
.fontSize(25)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 30 })
if (this.loading) {
Progress({})
.width(50)
.height(50)
.margin({ bottom: 20 })
}
List() {
ForEach(this.providers, provider => {
ListItem() {
Row() {
Text(provider.name)
.fontSize(18)
.layoutWeight(1)
if (provider.linked) {
Button('解绑')
.width(80)
.height(40)
.backgroundColor(Color.Red)
.fontColor(Color.White)
.onClick(() => this.handleUnlink(provider.id))
} else {
Button('绑定')
.width(80)
.height(40)
.backgroundColor(Color.Green)
.fontColor(Color.White)
.onClick(() => this.handleLink(provider.id))
}
}
.width('100%')
.padding(10)
}
})
}
.width('100%')
.layoutWeight(1)
if (this.message) {
Text(this.message)
.fontColor(this.message.includes('成功') ? Color.Green : Color.Red)
.margin({ top: 20 })
}
}
.width('100%')
.height('100%')
.padding(20)
}
}
第七部分:测试与发布
7.1 测试第三方登录
在DevEco Studio中运行应用
点击"微信登录"或"QQ登录"按钮
确认能够正确跳转到第三方应用并返回用户信息
验证用户信息页面显示正确
7.2 常见问题解决
登录失败,错误码1001:
检查AGC控制台中配置的微信/QQ AppID是否正确
确认包名和签名与第三方平台配置一致
无法获取用户信息:
检查是否在第三方平台申请了正确的权限
确认用户已授权提供基本信息
测试环境与正式环境问题:
微信平台需要单独申请测试权限
QQ平台测试需要使用测试账号
总结
通过本教程,你已经完成了:
在HarmonyOS 5应用中集成AGC认证服务
实现微信和QQ的第三方登录功能
管理用户信息和登录状态
实现账号绑定与解绑功能
关键点回顾:
统一认证入口:通过AGC认证服务统一管理各种登录方式
用户状态管理:合理处理登录状态变化和用户信息展示
多平台支持:灵活支持微信、QQ等多种第三方登录
安全考虑:正确处理令牌和用户敏感信息
通过第三方登录集成,你可以显著提升应用

浙公网安备 33010602011771号