# 企业微信认证方法文档 ## 概述 `WxworkAuth` 是一个灵活的企业微信认证工具类,提供可自由搭配的用户信息验证和登录方法。相比路由守卫 `WxworkAuthGuard` 的强制性限制,`WxworkAuth` 允许在页面中灵活调用,实现页面先加载、再执行用户信息同步和注册的流程。 **文件位置**: `fmode-ng/core.ts` --- ## 主要特性 1. **灵活可组合**: 提供独立的方法,可根据需求自由搭配使用 2. **页面内调用**: 可在组件的 `constructor` 或生命周期钩子中调用 3. **自动登录注册**: 使用 `userid` 作为用户名,后6位作为密码自动注册和登录 4. **支持多种场景**: - 只获取用户信息(不登录) - 只同步用户信息到数据库(不登录) - 自动登录/注册 - 一站式完整流程 --- ## 快速开始 ### 1. 基础引入 ```typescript import { WxworkAuth } from 'fmode-ng/core'; // 初始化 const wxAuth = new WxworkAuth({ cid: 'cDL6R1hgSi', // 公司帐套ID appId: 'crm' // 应用ID,可选,默认为 'crm' }); ``` ### 2. 在组件中使用(推荐场景) ```typescript import { Component } from '@angular/core'; import { WxworkAuth } from 'fmode-ng/core'; @Component({ selector: 'app-my-page', templateUrl: './my-page.component.html' }) export class MyPageComponent { wxAuth: WxworkAuth; userInfo: any; constructor() { this.wxAuth = new WxworkAuth({ cid: 'cDL6R1hgSi' }); // 页面加载后执行用户认证 this.initAuth(); } async initAuth() { try { // 方案1: 一站式认证和登录 const { userInfo, profile, user } = await this.wxAuth.authenticateAndLogin(); console.log('用户信息:', userInfo); console.log('Profile ID:', profile.id); console.log('登录用户:', user?.get('username')); this.userInfo = userInfo; } catch (error) { console.error('认证失败:', error); } } } ``` --- ## API 文档 ### 构造函数 ```typescript constructor(options: { cid: string; // 公司帐套ID,必填 appId?: string; // 应用ID,可选,默认为 'crm' }) ``` **示例**: ```typescript const wxAuth = new WxworkAuth({ cid: 'cDL6R1hgSi' }); ``` --- ### 方法列表 #### 1. `getUserInfo(code?: string): Promise` 获取企业微信用户信息(不登录) **参数**: - `code` (可选): 授权码,如果不提供则尝试从缓存或URL获取 **返回值**: 企业微信用户信息对象 ```typescript { userid?: string; // 企业员工ID external_userid?: string; // 外部联系人ID openid?: string; // 微信OpenID name?: string; // 姓名 mobile?: string; // 手机号 email?: string; // 邮箱 avatar?: string; // 头像URL gender?: number; // 性别 (1:男, 2:女) // ... 其他字段 } ``` **使用场景**: 只需要获取用户信息,不需要登录系统 **示例**: ```typescript const userInfo = await wxAuth.getUserInfo(); console.log('用户ID:', userInfo.userid); console.log('姓名:', userInfo.name); console.log('手机:', userInfo.mobile); ``` --- #### 2. `syncUserInfo(userInfo?: any): Promise` 同步用户信息到 `Profile`/`UserSocial` 表(不登录) **参数**: - `userInfo` (可选): 用户信息对象,如果不提供则自动调用 `getUserInfo()` 获取 **返回值**: `Profile` 或 `UserSocial` Parse Object **使用场景**: 只需要同步用户信息到数据库,不需要登录系统 **示例**: ```typescript // 方式1: 自动获取用户信息并同步 const profile = await wxAuth.syncUserInfo(); console.log('同步成功,Profile ID:', profile.id); // 方式2: 使用已有的用户信息 const userInfo = await wxAuth.getUserInfo(); const profile = await wxAuth.syncUserInfo(userInfo); ``` --- #### 3. `autoLogin(userInfo?: any): Promise` 自动登录或注册用户(使用 `userid` 和后6位作为密码) **参数**: - `userInfo` (可选): 用户信息对象,如果不提供则自动获取 **返回值**: `FmodeUser` 对象或 `null` **登录逻辑**: 1. 检查是否已登录,如果已登录直接返回当前用户 2. 使用 `userid` 或 `external_userid` 或 `openid` 作为用户名 3. 使用用户名的后6位作为密码 4. 尝试登录,如果用户不存在则自动注册 5. 同步 `user` 指针到 `Profile`/`UserSocial` **使用场景**: 需要用户登录系统才能访问功能 **示例**: ```typescript const user = await wxAuth.autoLogin(); if (user) { console.log('登录成功,用户名:', user.get('username')); } else { console.log('登录失败'); } ``` --- #### 4. `authenticateAndLogin(code?: string): Promise<{ userInfo, profile, user }>` 一站式方法:获取用户信息、同步、并自动登录/注册 **参数**: - `code` (可选): 授权码 **返回值**: ```typescript { userInfo: any; // 企业微信用户信息 profile: any; // Profile 或 UserSocial 对象 user: FmodeUser | null; // 登录的用户对象 } ``` **执行流程**: 1. 获取企业微信用户信息 2. 同步到 `Profile`/`UserSocial` 表 3. 自动登录/注册用户 **使用场景**: 最常用的场景,一次调用完成所有认证流程 **示例**: ```typescript const { userInfo, profile, user } = await wxAuth.authenticateAndLogin(); console.log('用户信息:', userInfo); console.log('Profile ID:', profile.id); console.log('登录用户:', user?.get('username')); ``` --- #### 5. `oauth(scope?, renew?): Promise` 触发 OAuth 授权流程 **参数**: - `scope` (可选): 授权类型 - `'snsapi_base'`: 静默授权(默认) - `'snsapi_privateinfo'`: 敏感信息授权 - `renew` (可选): 是否强制重新授权(清除缓存),默认 `false` **返回值**: 授权码或 `null`(如果跳转) **使用场景**: 需要手动触发授权流程 **示例**: ```typescript // 静默授权 await wxAuth.oauth('snsapi_base'); // 敏感信息授权 await wxAuth.oauth('snsapi_privateinfo'); // 强制重新授权 await wxAuth.oauth('snsapi_base', true); ``` --- #### 6. `loginPC(): Promise` PC端登录(弹出扫码面板) **返回值**: 授权码 **使用场景**: PC端扫码登录 **示例**: ```typescript const code = await wxAuth.loginPC(); console.log('获得授权码:', code); ``` --- #### 7. `getSDK(): WxworkSDK` 获取 `WxworkSDK` 实例(用于高级操作) **返回值**: `WxworkSDK` 实例 **使用场景**: 需要使用 SDK 的其他高级功能 **示例**: ```typescript const sdk = wxAuth.getSDK(); // 获取当前聊天对象 const { GroupChat, Contact } = await sdk.getCurrentChatObject(); // 同步群聊信息 const group = await sdk.syncGroupChat(groupInfo); ``` --- ## 使用场景示例 ### 场景1: 页面加载后自动登录 ```typescript @Component({ selector: 'app-dashboard', templateUrl: './dashboard.component.html' }) export class DashboardComponent implements OnInit { wxAuth: WxworkAuth; currentUser: any; constructor() { this.wxAuth = new WxworkAuth({ cid: 'cDL6R1hgSi' }); } async ngOnInit() { // 页面加载后自动认证和登录 const { user } = await this.wxAuth.authenticateAndLogin(); this.currentUser = user; if (!user) { // 处理登录失败的情况 console.error('用户登录失败'); } } } ``` --- ### 场景2: 只获取用户信息显示,不登录 ```typescript @Component({ selector: 'app-profile-preview', templateUrl: './profile-preview.component.html' }) export class ProfilePreviewComponent implements OnInit { wxAuth: WxworkAuth; userInfo: any; constructor() { this.wxAuth = new WxworkAuth({ cid: 'cDL6R1hgSi' }); } async ngOnInit() { // 只获取用户信息,不登录 this.userInfo = await this.wxAuth.getUserInfo(); console.log('用户名:', this.userInfo.name); } } ``` --- ### 场景3: 分步骤执行认证流程 ```typescript @Component({ selector: 'app-onboarding', templateUrl: './onboarding.component.html' }) export class OnboardingComponent { wxAuth: WxworkAuth; step = 1; userInfo: any; profile: any; constructor() { this.wxAuth = new WxworkAuth({ cid: 'cDL6R1hgSi' }); } async step1_getUserInfo() { this.userInfo = await this.wxAuth.getUserInfo(); this.step = 2; } async step2_syncProfile() { this.profile = await this.wxAuth.syncUserInfo(this.userInfo); this.step = 3; } async step3_login() { const user = await this.wxAuth.autoLogin(this.userInfo); if (user) { console.log('登录成功!'); // 跳转到主页 } } } ``` --- ### 场景4: 检查登录状态,未登录时才执行认证 ```typescript import { FmodeParse } from 'projects/fmode-ng/src/lib/core/parse'; const Parse = FmodeParse.with("nova"); async function ensureAuthenticated() { const currentUser = Parse.User.current(); if (currentUser) { console.log('用户已登录:', currentUser.get('username')); return currentUser; } // 未登录,执行认证 const wxAuth = new WxworkAuth({ cid: 'cDL6R1hgSi' }); const { user } = await wxAuth.authenticateAndLogin(); return user; } ``` --- ## 与路由守卫的区别 ### `WxworkAuthGuard` (路由守卫) **特点**: - 在路由激活前强制执行认证 - 阻塞页面加载,直到认证完成 - 适合需要强制登录的路由 **限制**: - 页面无法先加载 - 灵活性较低 - 无法根据页面逻辑自定义认证流程 **使用方式**: ```typescript const routes: Routes = [ { path: 'protected', component: ProtectedComponent, canActivate: [WxworkAuthGuard] } ]; ``` --- ### `WxworkAuth` (认证工具类) **特点**: - 页面可以先加载 - 在 `constructor` 或生命周期钩子中灵活调用 - 可根据页面逻辑自定义认证流程 - 可选择性执行部分认证步骤 **优势**: - 更好的用户体验(页面先显示) - 灵活可组合 - 适合复杂的业务逻辑 **使用方式**: ```typescript // 在组件中直接调用 const wxAuth = new WxworkAuth({ cid: 'cDL6R1hgSi' }); await wxAuth.authenticateAndLogin(); ``` --- ## 最佳实践 ### 1. 统一认证服务 创建一个 Angular Service 来统一管理认证逻辑: ```typescript import { Injectable } from '@angular/core'; import { WxworkAuth } from 'fmode-ng/core'; @Injectable({ providedIn: 'root' }) export class AuthService { private wxAuth: WxworkAuth; constructor() { // 从环境变量或配置中获取 cid this.wxAuth = new WxworkAuth({ cid: 'cDL6R1hgSi' }); } async authenticate() { return await this.wxAuth.authenticateAndLogin(); } async getUserInfo() { return await this.wxAuth.getUserInfo(); } } ``` 在组件中使用: ```typescript @Component({ selector: 'app-my-page', templateUrl: './my-page.component.html' }) export class MyPageComponent implements OnInit { constructor(private authService: AuthService) {} async ngOnInit() { const { user } = await this.authService.authenticate(); console.log('当前用户:', user?.get('username')); } } ``` --- ### 2. 错误处理 ```typescript async initAuth() { try { const { user } = await this.wxAuth.authenticateAndLogin(); if (!user) { // 认证成功但登录失败 this.showMessage('登录失败,请稍后再试'); return; } // 登录成功 this.onLoginSuccess(user); } catch (error: any) { // 认证失败 console.error('认证错误:', error); if (error.message?.includes('无法获取用户信息')) { this.showMessage('无法获取用户信息,请检查网络'); } else { this.showMessage('认证失败,请重试'); } } } ``` --- ### 3. 配置管理 使用环境变量管理不同环境的配置: ```typescript // environment.ts export const environment = { production: false, wxwork: { cid: 'cDL6R1hgSi', appId: 'crm' } }; // 使用 import { environment } from 'src/environments/environment'; const wxAuth = new WxworkAuth({ cid: environment.wxwork.cid, appId: environment.wxwork.appId }); ``` --- ## 注意事项 1. **cid 配置**: 确保 `cid` 在 `WxworkSDK.companyMap` 中有对应的配置 2. **错误处理**: 所有方法都会抛出错误,请使用 `try-catch` 捕获 3. **缓存机制**: `getUserInfo()` 会优先使用 localStorage 缓存,传入 `code` 可强制刷新 4. **密码规则**: 自动登录使用 `userid` 后6位作为密码,确保 `userid` 长度 ≥ 6 5. **类型转换**: `Parse.User` 需要转换为 `FmodeUser` 类型:`user as FmodeUser` --- ## 相关文件 - **认证工具类**: `fmode-ng/core.ts` - **路由守卫**: `projects/fmode-ng/src/lib/social/wxwork/wxwork-auth.guard.ts` - **SDK**: `projects/fmode-ng/src/lib/core/social/wxwork/wxwork.sdk.ts` - **企业API**: `projects/fmode-ng/src/lib/core/social/wxwork/wxwork.corp.ts` --- ## 技术支持 如遇问题,请检查: 1. 企业微信配置是否正确(`corpId`, `agentId`, `suiteId`) 2. 回调域名是否已配置 3. `cid` 是否在 `companyMap` 中存在 4. 网络请求是否正常 5. 浏览器控制台是否有错误信息