求有代码 集成第三方登录: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等多种第三方登录
​​安全考虑​​:正确处理令牌和用户敏感信息
通过第三方登录集成,你可以显著提升应用

posted @ 2025-06-28 22:57  暗雨YA  阅读(91)  评论(0)    收藏  举报