这个文档提供企业微信 OAuth 2.0 认证的后端实现指南。前端会将授权码发送到后端,后端使用该授权码与企业微信服务器交互获取用户信息。
┌─────────────┐ ┌──────────────┐ ┌──────────────┐
│ 前端页面 │ │ 企业微信 │ │ 后端服务 │
│ │ │ OAuth 服务 │ │ │
└──────┬──────┘ └──────────────┘ └──────────────┘
│ │ │
│ 1. 获取授权码 │ │
├──────────────────────>│ │
│ (重定向到授权页面) │ │
│ │ │
│ 2. 用户授权 │ │
│ (返回授权码和code) │ │
│<──────────────────────┤ │
│ │ │
│ 3. 发送授权码到后端 │ │
├─────────────────────────────────────────────────>│
│ (POST /api/wecom/getUserInfo) │
│ │ │
│ │ 4. 使用 code 和 secret │
│ │ 交换 access_token │
│ │<────────────────────────┤
│ │ │
│ 5. 返回用户信息 │ │
│<─────────────────────────────────────────────────┤
│ │ │
请求
```
POST /api/wecom/getUserInfo
Content-Type: application/json
{
"code": "获取的授权码"
}
```
响应json { "code": 0, "message": "success", "data": { "userid": "user123", "name": "张三", "mobile": "13800138000", "email": "zhang@company.com", "department": "技术部", "position": "工程师" } }
请求 GET /api/wecom/verify/:userId
响应json { "code": 0, "message": "success", "data": { "authorized": true } }
// 需要安装: npm install axios dotenv
const express = require('express');
const axios = require('axios');
require('dotenv').config();
const router = express.Router();
// 获取访问令牌
async function getAccessToken() {
try {
const response = await axios.get(
'https://qyapi.weixin.qq.com/cgi-bin/gettoken',
{
params: {
corpid: process.env.WECOM_CORP_ID,
corpsecret: process.env.WECOM_APP_SECRET
}
}
);
return response.data.access_token;
} catch (error) {
console.error('获取 access_token 失败:', error);
throw error;
}
}
// 使用授权码获取用户信息
router.post('/wecom/getUserInfo', async (req, res) => {
const { code } = req.body;
if (!code) {
return res.status(400).json({
code: -1,
message: '缺少授权码'
});
}
try {
const accessToken = await getAccessToken();
// 使用授权码获取用户身份信息
const userResponse = await axios.get(
'https://qyapi.weixin.qq.com/cgi-bin/auth/getuserdetail',
{
params: {
access_token: accessToken,
code: code
}
}
);
if (userResponse.data.errcode === 0) {
const userInfo = {
userid: userResponse.data.userid,
name: userResponse.data.name,
mobile: userResponse.data.mobile,
email: userResponse.data.email,
department: userResponse.data.department?.[0] || '',
position: userResponse.data.position
};
// 可以在这里存储用户信息到数据库
res.json({
code: 0,
message: 'success',
data: userInfo
});
} else {
res.status(401).json({
code: userResponse.data.errcode,
message: userResponse.data.errmsg
});
}
} catch (error) {
console.error('获取用户信息失败:', error);
res.status(500).json({
code: -1,
message: '获取用户信息失败'
});
}
});
// 验证用户权限
router.get('/wecom/verify/:userId', async (req, res) => {
const { userId } = req.params;
try {
// 实现你的权限验证逻辑
const authorized = await checkUserPermission(userId);
res.json({
code: 0,
message: 'success',
data: {
authorized: authorized
}
});
} catch (error) {
console.error('验证用户权限失败:', error);
res.status(500).json({
code: -1,
message: '验证失败'
});
}
});
module.exports = router;
# 企业微信配置
WECOM_CORP_ID=your_corp_id
WECOM_APP_SECRET=your_app_secret
WECOM_AGENT_ID=your_agent_id
# 应用配置
NODE_ENV=production
PORT=3000
from flask import Blueprint, request, jsonify
import requests
import os
wecom_bp = Blueprint('wecom', __name__, url_prefix='/api')
def get_access_token():
"""获取企业微信访问令牌"""
url = 'https://qyapi.weixin.qq.com/cgi-bin/gettoken'
params = {
'corpid': os.getenv('WECOM_CORP_ID'),
'corpsecret': os.getenv('WECOM_APP_SECRET')
}
response = requests.get(url, params=params)
data = response.json()
return data.get('access_token')
@wecom_bp.route('/wecom/getUserInfo', methods=['POST'])
def get_user_info():
"""使用授权码获取用户信息"""
code = request.json.get('code')
if not code:
return jsonify({
'code': -1,
'message': '缺少授权码'
}), 400
try:
access_token = get_access_token()
# 获取用户身份信息
url = 'https://qyapi.weixin.qq.com/cgi-bin/auth/getuserdetail'
params = {
'access_token': access_token,
'code': code
}
response = requests.get(url, params=params)
data = response.json()
if data.get('errcode') == 0:
user_info = {
'userid': data.get('userid'),
'name': data.get('name'),
'mobile': data.get('mobile'),
'email': data.get('email'),
'department': data.get('department', [])[0] if data.get('department') else '',
'position': data.get('position')
}
return jsonify({
'code': 0,
'message': 'success',
'data': user_info
})
else:
return jsonify({
'code': data.get('errcode'),
'message': data.get('errmsg')
}), 401
except Exception as e:
return jsonify({
'code': -1,
'message': f'获取用户信息失败: {str(e)}'
}), 500
@wecom_bp.route('/wecom/verify/<user_id>', methods=['GET'])
def verify_user(user_id):
"""验证用户权限"""
try:
# 实现你的权限验证逻辑
authorized = check_user_permission(user_id)
return jsonify({
'code': 0,
'message': 'success',
'data': {
'authorized': authorized
}
})
except Exception as e:
return jsonify({
'code': -1,
'message': '验证失败'
}), 500
常见错误码:
- 40001: access_token 过期
- 40013: 非法的 secret
- 40014: 无效的用户ID
- 82001: 参数错误
企业微信可能会发送消息给应用,需要验证签名:
function verifySignature(timestamp, nonce, msgEncrypt, token, encodingAESKey) {
// 实现签名验证逻辑
// 按照文档进行 SHA1 校验
}
使用 curl 测试 API:
# 获取用户信息
curl -X POST http://localhost:3000/api/wecom/getUserInfo \
-H "Content-Type: application/json" \
-d '{"code": "your_auth_code"}'
# 验证用户权限
curl http://localhost:3000/api/wecom/verify/user123
Q: 如何处理 Token 过期?
A: 实现 Token 刷新机制,当收到 40001 错误时重新获取 access_token。
Q: 如何限制访问范围?
A: 在后端验证用户身份后,根据用户的部门和角色进行权限判断。
Q: 可以获取用户哪些信息?
A: 根据授权范围(scope)和应用权限,可获取用户ID、名称、手机、邮箱、部门等。