wechatPublic

This commit is contained in:
Wang Kejun 2022-08-03 11:33:04 +08:00
parent c46a5bbf93
commit 951e640164
3 changed files with 106 additions and 3 deletions

View File

@ -1,19 +1,23 @@
import { WechatMpInstance } from './service/wechat/WechatMp';
import { WechatPublicInstance } from './service/wechat/WechatPublic';
class WechatSDK {
mpMap: Record<string, WechatMpInstance>;
publicMap: Record<string, any>;
webMap: Record<string, any>;
constructor() {
this.mpMap = {};
this.publicMap = {};
this.webMap = {};
}
getInstance(
appId: string,
appSecret: string,
type: 'wechatMp' | 'wechatPublic'
type: 'wechatMp' | 'wechatPublic' | 'web'
) {
// type 支持web网站扫码登录
if (type === 'wechatMp') {
if (this.mpMap[appId]) {
return this.mpMap[appId];
@ -23,6 +27,15 @@ class WechatSDK {
[appId]: instance,
});
return instance;
} else if (type === 'wechatPublic') {
if (this.publicMap[appId]) {
return this.publicMap[appId];
}
const instance = new WechatPublicInstance(appId, appSecret);
Object.assign(this.publicMap, {
[appId]: instance,
});
return instance;
} else {
throw new Error('public not implemented');
}

View File

@ -6,7 +6,7 @@ export class WechatMpInstance {
appSecret: string;
accessToken?: string;
refreshAcessTokenHandler?: any;
refreshAccessTokenHandler?: any;
constructor(appId: string, appSecret: string) {
this.appId = appId;
@ -61,7 +61,7 @@ export class WechatMpInstance {
const { access_token, expires_in } = result;
this.accessToken = access_token;
// 生成下次刷新的定时器
this.refreshAcessTokenHandler = setTimeout(() => {
this.refreshAccessTokenHandler = setTimeout(() => {
this.refreshAccessToken();
}, (expires_in - 10) * 1000);
}

View File

@ -0,0 +1,90 @@
import crypto from 'crypto';
import { Buffer } from 'buffer';
export class WechatPublicInstance {
appId: string;
appSecret: string;
accessToken?: string;
refreshAccessTokenHandler?: any;
constructor(appId: string, appSecret: string) {
this.appId = appId;
this.appSecret = appSecret;
this.refreshAccessToken();
}
private async access(url: string, init?: RequestInit) {
const response = await fetch(url, init);
const { headers, status } = response;
if (![200, 201].includes(status)) {
throw new Error(`微信服务器返回不正确应答:${status}`);
}
const contentType = (headers as any)['Content-Type'] || headers.get('Content-Type')!;
if (contentType.includes('application/json')) {
const json = await response.json();
if (typeof json.errcode === 'number' && json.errcode !== 0) {
throw new Error(`调用微信接口返回出错code是${json.errcode},信息是${json.errmsg}`);
}
return json;
}
if (
contentType.includes('text')
|| contentType.includes('xml')
|| contentType.includes('html')
) {
const data = await response.text();
return data;
}
if (contentType.includes('application/octet-stream')) {
return await response.arrayBuffer();
}
return response;
}
async code2Session(code: string) {
const result = await this.access(`https://api.weixin.qq.com/sns/oauth2/access_token?appid=${this.appId}&secret=${this.appSecret}&code=${code}&grant_type=authorization_code`);
const { session_key, openid, unionid } = JSON.parse(result); // 这里微信返回的数据竟然是text/plain
return {
sessionKey: session_key as string,
openId: openid as string,
unionId: unionid as string,
};
}
private async refreshAccessToken() {
const result = await this.access(`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${this.appId}&secret=${this.appSecret}`);
const { access_token, expires_in } = result;
this.accessToken = access_token;
// 生成下次刷新的定时器
this.refreshAccessTokenHandler = setTimeout(() => {
this.refreshAccessToken();
}, (expires_in - 10) * 1000);
}
decryptData(sessionKey: string, encryptedData: string, iv: string, signature: string) {
const skBuf = Buffer.from(sessionKey, 'base64');
// const edBuf = Buffer.from(encryptedData, 'base64');
const ivBuf = Buffer.from(iv, 'base64');
const decipher = crypto.createDecipheriv('aes-128-cbc', skBuf, ivBuf);
// 设置自动 padding 为 true删除填充补位
decipher.setAutoPadding(true);
let decoded = decipher.update(encryptedData, 'base64', 'utf8');
decoded += decipher.final('utf8');
const data = JSON.parse(decoded);
if (data.watermark.appid !== this.appId) {
throw new Error('Illegal Buffer');
}
return data;
}
};