--- title: 企业微信工作台开发 date: 2026-01-23 --- # 一、建立工作台 1. 进入企业微信后台管理系统,选择应用管理->应用管理。 2. 选择自建->创建应用。 3. 输入名称、图标等信息,分配可见范围,完成应用创建. 4. 点击应用,选择开发者接口->网页授权,配置可信域名和企业可信IP。 5. 查看并保存AgentId和Secret。 ::: tip 可信域名不能是IP形式,必须是和企业微信备案主体一致的服务器。 ::: # 二、JS-SDK开发 ## 2.1 接口鉴权 [官方文档](https://developer.work.weixin.qq.com/document/path/90514) 参考第三节企业微信鉴权接口开发 ## 2.2 打开默认浏览器 使用系统浏览器打开指定 URL,支持传入 oauth2 链接,从而实现在系统浏览器内免登录的效果。 # 三、鉴权接口开发 本教程以node.js为例。 ## 3.1 通用企业微信服务端API ```js const axios = require('axios'); const TOKEN_URL = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken' const JSAPI_TICKET_URL = 'https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket' const MESSAGE_URL = 'https://qyapi.weixin.qq.com/cgi-bin/message/send' // 获取access_token async function getAccessTokenApi(corpId, corpSecret) { const now = Date.now(); try { const url = `${TOKEN_URL}?corpid=${corpId}&corpsecret=${corpSecret}` const response = await axios.get(url); if (response.data.errcode === 0) { return { accessToken: response.data.access_token, expires: now + (response.data.expires_in - 300) * 1000 // 提前5分钟过期 }; } else { throw new Error(`获取access_token失败: ${response.data.errmsg}`); } } catch (error) { console.error('获取access_token错误:', error); throw error; } } // 获取jsapi_ticket async function getJsapiTicketApi(accessToken) { try { const url = `${JSAPI_TICKET_URL}?access_token=${accessToken}` const response = await axios.get(url); if (response.data.errcode === 0) { return response.data.ticket; } else { throw new Error(`获取jsapi_ticket失败: ${response.data.errmsg}`); } } catch (error) { console.error('获取jsapi_ticket错误:', error); throw error; } } // 发送应用消息 async function sendMessageApi(agentid, accessToken, touser, content) { try { const url = `${MESSAGE_URL}?access_token=${accessToken}` const response = await axios.post(url, { touser: touser, msgtype: 'text', agentid: agentid, text: { content: content } }); if (response.data.errcode === 0) { return true; } else { throw new Error(`发送应用消息失败: ${response.data.errmsg}`); } } catch (error) { console.error('发送应用消息错误:', error); throw error; } } module.exports = { getAccessTokenApi, getJsapiTicketApi, sendMessageApi }; ``` ## 3.2 自建应用鉴权接口 ```js const {getAccessTokenApi, getJsapiTicketApi, sendMessageApi} = require("./wecom"); const config = { corpId: '', // 企业id corpSecret: '', // 应用密码 agentId: '', // 应用id domain: '', // 跳转域名 password: '' // 登录默认密码 }; // 存储access_token和jsapi_ticket let tokenCache = { accessToken: null, jsapiTicket: null, expires: 0 }; // 获取access_token async function getRepairAccessToken() { const now = Date.now(); if (tokenCache.accessToken && tokenCache.expires > now) { return tokenCache.accessToken; } const result = await getAccessTokenApi(config.corpId, config.corpSecret) tokenCache.accessToken = result.accessToken; tokenCache.expires = result.expires } // 获取jsapi_ticket async function getRepairJsapiTicket() { const now = Date.now(); if (tokenCache.jsapiTicket && tokenCache.expires > now) { return tokenCache.jsapiTicket; } await getRepairAccessToken(); tokenCache.jsapiTicket = await getJsapiTicketApi(tokenCache.accessToken); } // 发送应用消息 async function sendRepairMessage(touser, content) { await getRepairAccessToken(); await sendMessageApi(config.agentId, tokenCache.accessToken, touser, content); } function getRepairDomain() { return config.domain } function getRepairPassword() { return config.password } module.exports = { getRepairAccessToken, getRepairJsapiTicket, sendRepairMessage, getRepairDomain, getRepairPassword }; ``` ## 3.3 NodeJS API ```js const express = require('express'); const axios = require('axios'); const cors = require('cors'); const {generateNonceStr, generateSignature} = require("./utils"); const {sendRepairMessage, getRepairJsapiTicket, getRepairAccessToken, getRepairDomain, getRepairPassword} = require("./repair"); const app = express(); const PORT = 3000; app.use(cors()); app.use(express.json()); const corpId = 'ww48932728388c9e3a' const USER_INFO_URL = 'https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo' // API接口:生成JS-SDK配置 app.post('/auth/config/repair', async (req, res) => { await configService(req, res, 'repair') }); async function configService(req, res, appName) { try { const {url} = req.body; if (!url) { return res.status(400).json({errcode: -1, errmsg: '缺少url参数'}); } let jsapiTicket = '' if (appName === 'repair') { jsapiTicket = await getRepairJsapiTicket(); } const timestamp = Math.floor(Date.now() / 1000); const noncestr = generateNonceStr(); const signature = generateSignature(jsapiTicket, noncestr, timestamp, url); res.json({ errcode: 0, errmsg: 'ok', appId: corpId, timestamp, nonceStr: noncestr, signature }); } catch (error) { console.error('生成JS-SDK配置错误:', error); res.status(500).json({errcode: -1, errmsg: '服务器内部错误'}); } } // API接口:OAuth回调处理 app.get('/auth/callback/repair', async (req, res) => { await callback(req, res, 'repair') }); async function callback(req, res, appName) { try { const {code, state} = req.query; if (!code) { return res.status(400).send('缺少code参数'); } // 通过code获取用户信息 let accessToken = '' if (appName === 'repair') { accessToken = await getRepairAccessToken(); } const url = `${USER_INFO_URL}?access_token=${accessToken}&code=${code}` const userResponse = await axios.get(url); if (userResponse.data.errcode !== 0) { throw new Error(`获取用户信息失败: ${userResponse.data.errmsg}`); } const userInfo = userResponse.data; // 重定向到前端页面 let redirectUrl = '' if (appName === 'repair') { redirectUrl = `${getRepairDomain()}?username=${userInfo.UserId}&password=${getRepairPassword()}&type=repair`; } res.redirect(redirectUrl); } catch (error) { console.error('OAuth回调处理错误:', error); res.status(500).send(`
${error.message}
`); } } // API接口:发现应用消息 app.post('/message/repair', async (req, res) => { const {touser, content} = req.body; await sendRepairMessage(touser, content) res.json({ errcode: 0, errmsg: 'ok' }); }); // 启动服务 app.listen(PORT, () => { console.log(`企业微信登录服务运行在端口 ${PORT}`); }); module.exports = app; ``` ## 3.4 工具类 ```js const crypto = require('crypto'); // 工具函数:生成随机字符串 function generateNonceStr(length = 16) { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; let result = ''; for (let i = 0; i < length; i++) { result += chars.charAt(Math.floor(Math.random() * chars.length)); } return result; } // 工具函数:生成签名 function generateSignature(jsapiTicket, noncestr, timestamp, url) { const string = `jsapi_ticket=${jsapiTicket}&noncestr=${noncestr}×tamp=${timestamp}&url=${url}`; return crypto.createHash('sha1').update(string).digest('hex'); } module.exports = { generateNonceStr, generateSignature }; ``` # 四、应用主页 ```html