-
Notifications
You must be signed in to change notification settings - Fork 347
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Invite @willin to post a Wechaty Authing plugin project tutorial blog at here #1464
Comments
用户故事其实用 Authing 团队管理 + Wechaty 机器人能够实现很多功能,来提高传统人事管理的效率。甚至还可以做一些数据的分析、统计,来辅助决策。这里我就列了几个简单的现实场景,希望能帮助大家理解。 以 Authing 作为上游数据源同步数据到其他平台,前期为飞书和微信。创建完用户后,用户可以通过手机号直接登录飞书。个人微信添加 Wechaty Bot,通过消息发送手机号进行用户关联绑定。在 Authing 中创建组织架构,同步对应创建飞书的部门和微信的群组。同步删除飞书用户、微信群移除群聊。 原有飞书组织接入微信飞书作为上游数据源。微信添加 Wechat Bot,通过消息发送手机号进行用户关联绑定。 原有微信群组并接入飞书选择一个全员微信群进行接入,首先 Wechaty Bot 会为该群中所有成员创建 Authing 用户。微信添加 Wechaty Bot 或者 @提及的方式发送消息手机号进行用户关联绑定,绑定手机号的成员可以通过该手机号进行飞书的登录。 撸一个 Wechaty Authing 的插件也可以通过插件的介绍页面直接去了解插件的使用说明。该插件开源代码仓库位于: https://github.com/Authing/wechaty-authing 设计思路
实现在着手开发这个插件之前,我是分别以 Wechaty 作为用户上游和 Authing 用户池作为用户上游做了两个 MVP 项目。然后通过项目中的一些方法和功能,来完成这个插件的最初版本。 列举一下 Wechaty 作为用户上游时,需要用到的一些方法:
再列举一下将 Authing 作为用户上游时,需要用到的一些方法:
然后这个过程中,经常会有两个用户列表的比较,一个是 Wechaty 最后代码大概的框架成了这个样子: export class WechatyAuthing {
constructor(config: WechatyAuthingConfig);
/**
* Get Authing SDK client
* 获取 Authing SDK 实例
*/
protected get client(): _ManagementClient1;
/**
* Get Authing User pool name
* @returns {Promise<string>}
*/
getPoolName(): Promise<string>;
/** ********* AS UPSTREAM ************* */
/**
* Batch check users exists from Authing
* 检查是否注册为 Authing 用户
* @param {Contact[]} contacts Wechaty Contact[]
* @returns {ContactsFilterResult} { registered: Contact[]; unregistered: Contact[]; fail: Contact[] }
*/
filterAuthingUsers<T = Contact>(
contacts: T[]
): Promise<ContactsFilterResult<T>>;
/**
* Batch create users to Authing
* 向 Authing 用户池中批量创建用户
* @param {Contact[]} contacts Wechaty Contact[]
* @returns {ContactsOperationResult} {success: Contact[], fail: Contact[]}
*/
createAuthingUsers<T = Contact>(
contacts: T[]
): Promise<ContactsOperationResult<T>>;
/**
* Batch delete users from Authing
* 从 Authing 用户池中批量删除 Wechaty 用户
* @param {Contact[]} contacts Wechaty Contact[]
* @returns {ContactsOperationResult} {success: Contact[], fail: Contact[]} */
deleteAuthingUsers<T = Contact>(
contacts: T[]
): Promise<ContactsOperationResult<T>>;
/**
* Create or update a authing user with Wechaty contact and phone
* 绑定 Contact 和手机号码到 Authing 用户(或创建一个用户)
* @param {Contact} contact
* @param {string} phone
* @returns {Promise<boolean>}
*/
bindAuthingPhone<T = Contact>(contact: T, phone: string): Promise<boolean>;
/** ********* AS DOWNSTREAM ************* */
/**
* Check if user with the phone number exists in Authing
* 检查手机号是否注册为 Authing 用户
* @param {string} phone
* @returns {Promise<boolean>}
*/
checkPhone(phone: string): Promise<boolean>;
/**
* Bind Wechaty contact to a Authing user by phone number
* 将 Wechaty Contact 绑定到 Authing 手机号的用户
* @param {string} phone
* @param {Contact} contact
* @returns {Promise<boolean>}
*/
bindPhoneContact<T = Contact>(phone: string, contact: T): Promise<boolean>;
/** ********* PROTECTED ************* */
/**
* Create Authing user
* 创建 Authing 用户
* @param {Contact} contact
* @returns {User | null}
*/
protected createAuthingUser<T = Contact>(contact: T): Promise<User | null>;
} 另外,在刚开始 POC 的时候,我使用了大量低效的代码去实现该功能,如: // 筛选出用户中的好友
const friends = allFriends.filter(
(contact) => ~users.findIndex((user) => user.externalId === contact.id)
);
// 删除成员和提醒不确定状态
const members2Delete = memberList.filter(
(member) => ~deletedUsers.findIndex((user) => user.externalId === member.id)
);
const members2Warning = memberList.filter(
(member) =>
!~deletedUsers.findIndex((user) => user.externalId === member.id) &&
!~users.findIndex((user) => user.externalId === member.id)
);
// 检查未入群的好友
const members2Invite = friends.filter(
(friend) => !~memberList.findIndex((member) => member.id === friend.id)
); 在此基础上,优化了几个工具方法:
其实在集成过程中还有很多细节的点需要注意,我会都在文章最后的章节里进行整理。 测试目前的代码质量 A,测试覆盖率为 98%。如果你对于这个插件感兴趣,测试用例不仅仅是你参与贡献的最好开始,其实也是插件使用的绝佳案例。 其中也包括了示例初始化、各个方法调用和返回值期待、工具方法的使用,以及扩展开发的一些细节。 以拓展插件的测试用例为例: //https://github.com/Authing/wechaty-authing/blob/main/test/extends.spec.ts
import { WechatyAuthing } from '../src';
describe('extension', () => {
it('client', async () => {
class ExtendedWechatyAuthing extends WechatyAuthing {
async totalUsers(): Promise<number> {
const { totalCount } = await this.client.users.list();
return totalCount;
}
}
const client = new ExtendedWechatyAuthing({
userPoolId: process.env.AUTHING_USER_POOL_ID,
secret: process.env.AUTHING_USER_POOL_SECRET
});
const count = await client.totalUsers();
expect(count).toBeGreaterThan(0);
});
}); 当然,具体的插件使用细节,可以通过项目 README 文件查看,提供了中英文两个版本。 上手做几个机器人吧示例中(来自 POC 项目)使用的 Wechaty 版本为 使用微信群作为上游用户数据管理员邀请用户加入群组(人为操作)侦听 管理员踢出群聊用户(人为操作)侦听 如果有删除失败的(不确定原因引起),提示删除失败的用户名(列表),请管理员手动删除。 用户 @bot 提及消息侦听 检查用户是否存在,如果存在,修改绑定的手机号为用户输入的(可能出现重复手机号绑定失败);如果用户不存在注册一个新用户。 如果绑定成功,发送消息提示。 实现代码位于 POC 项目 首先在 Bot 启动时,进行一遍群成员的检查: 同时还侦听了两个 Wechaty 事件:
代码之外当微信用户绑定到 Authing 用户池之后,还可以做些什么呢?比如同步企业成员信息到飞书,连接到各种 SSO 单点登录应用等。发挥想象力的时间到了,改变生产力,或许并不是那么遥不可及的事情。 以 Authing 用户作为上游, Wechaty 用户作为下游用户数据来源也可能是同步中心里来自飞书或其他身份源的用户数据。其中有一步,在 Authing 用户池中添加新用户后,要求用户主动添加 Bot 为好友,必须。 在 Bot 启动时,检查微信中是否存在全员群,如果没有,就创建一个(但如果企业成员数量不够 3 个,不能创建群聊的时候,机器人就会等主动添加的好友)。全员群存在之后,就开始定时任务检查是否有离职成员需要踢出群聊,以及新入职的成员邀请加入群聊了。 其中,关联 Authing 用户和 Wechaty 联系人的方式也很简单。就是通过好友请求或者消息,发送手机号码,检查 Authing 用户池中是否存在。 扩展 wechaty-authing 插件去实现更复杂的业务扩展 Authing SDK 的使用
所以可以参考 Authing 官方的文档进行深度开发。示例: class ExtendedWechatyAuthing extends WechatyAuthing {
async totalUsers(): Promise<number> {
const { totalCount } = await this.client.users.list();
return totalCount;
}
} 参考文档: https://docs.authing.cn/v2/reference/sdk-for-node/management/ 扩展 Wechaty 插件同时开可以封装一些 Wechaty 插件功能。示例: class ExtendedWechatyAuthing extends WechatyAuthing {
plugin(): WechatyPlugin {
return (bot: Wechaty): void => {
bot.on('ready', async () => {
const { totalCount } = await this.client.users.list();
log.info('total users', totalCount);
});
};
}
}
const authing = new ExtendedWechatyAuthing({
userPoolId: process.env.AUTHING_USER_POOL_ID,
secret: process.env.AUTHING_USER_POOL_SECRET
});
const bot = createBot(process.env.WECHATY_PADLOCAL_TOKEN);
bot.use(authing.plugin()); 更多关于 Wechaty 插件的使用及开发,可以访问: https://wechaty.js.org/docs/using-plugin-with-wechaty/overview 注意事项微信限制
Wechaty Contact 唯一 ID 说明目前已知的 id 格式:
Wechaty 可能会出现的一些问题版本Wechaty 1.x 版本与之前的版本差距,如类型声明、创建实例的方式,需要注意你使用的 主动搜索有两种搜索方式,通过手机号和通过微信号: const contact = await this.Friendship.search({ phone: user.phone! });
const contact = await this.Friendship.search({ weixin: user.externalId! }); 获得的结果均无法获取到唯一 id:
解决:如果是好友,则可以从 contact.payload.id 中获得。 异常请求失败比如查找某个手机号或者微信号,填写的参数正确。
获取的信息不准确如 完整的数据应该是这样: [
{
_events: {},
_eventsCount: 0,
id: 'xxxx',
payload: {
id: 'xxxx',
gender: 1,
type: 1,
name: 'Willin',
avatar:
'https://wx.qlogo.cn/mmhead/ver_1/lY8XLaibGJAiajvtTPx5kdDs2T3qGToUm0mHFTYGRzcaVydJZwnibQKMNKDzv2WosXJu2aUU8lteT1R6FCKVK3PUg/0',
alias: '',
weixin: '',
city: 'Lianyungang',
friend: true,
province: 'Jiangsu',
signature: '所有的出发 \n都是为了回家',
phone: []
}
}
]; 有的时候会变成这样: [
{
_events: {},
_eventsCount: 0,
id: 'xxxx'
}
]; Refs
|
Could you please convert your post to a Pull Request so that it can be publish by the Jekyll system? Thank you very much! |
The Authing & Wechaty have been planning to publish a plugin for authorization between the Authing service and the Wechaty rooms in the past months, and now it seems we have great progress!
According to the issue
It seems that we have a great blog post for this project at https://blog.csdn.net/jslygwx/article/details/122624821
I would love to invite @willin to cross-post this great blog to our official website so that it can be better promoted with the Wechaty community.
Thank you very much @willin for accepting my invitation, looking forward to reading your great blog post on our website!
The text was updated successfully, but these errors were encountered: