wechatPublic
This commit is contained in:
parent
c46a5bbf93
commit
951e640164
|
|
@ -1,19 +1,23 @@
|
||||||
import { WechatMpInstance } from './service/wechat/WechatMp';
|
import { WechatMpInstance } from './service/wechat/WechatMp';
|
||||||
|
import { WechatPublicInstance } from './service/wechat/WechatPublic';
|
||||||
|
|
||||||
class WechatSDK {
|
class WechatSDK {
|
||||||
mpMap: Record<string, WechatMpInstance>;
|
mpMap: Record<string, WechatMpInstance>;
|
||||||
publicMap: Record<string, any>;
|
publicMap: Record<string, any>;
|
||||||
|
webMap: Record<string, any>;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.mpMap = {};
|
this.mpMap = {};
|
||||||
this.publicMap = {};
|
this.publicMap = {};
|
||||||
|
this.webMap = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
getInstance(
|
getInstance(
|
||||||
appId: string,
|
appId: string,
|
||||||
appSecret: string,
|
appSecret: string,
|
||||||
type: 'wechatMp' | 'wechatPublic'
|
type: 'wechatMp' | 'wechatPublic' | 'web'
|
||||||
) {
|
) {
|
||||||
|
// type 支持web网站扫码登录
|
||||||
if (type === 'wechatMp') {
|
if (type === 'wechatMp') {
|
||||||
if (this.mpMap[appId]) {
|
if (this.mpMap[appId]) {
|
||||||
return this.mpMap[appId];
|
return this.mpMap[appId];
|
||||||
|
|
@ -23,6 +27,15 @@ class WechatSDK {
|
||||||
[appId]: instance,
|
[appId]: instance,
|
||||||
});
|
});
|
||||||
return 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 {
|
} else {
|
||||||
throw new Error('public not implemented');
|
throw new Error('public not implemented');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ export class WechatMpInstance {
|
||||||
appSecret: string;
|
appSecret: string;
|
||||||
|
|
||||||
accessToken?: string;
|
accessToken?: string;
|
||||||
refreshAcessTokenHandler?: any;
|
refreshAccessTokenHandler?: any;
|
||||||
|
|
||||||
constructor(appId: string, appSecret: string) {
|
constructor(appId: string, appSecret: string) {
|
||||||
this.appId = appId;
|
this.appId = appId;
|
||||||
|
|
@ -61,7 +61,7 @@ export class WechatMpInstance {
|
||||||
const { access_token, expires_in } = result;
|
const { access_token, expires_in } = result;
|
||||||
this.accessToken = access_token;
|
this.accessToken = access_token;
|
||||||
// 生成下次刷新的定时器
|
// 生成下次刷新的定时器
|
||||||
this.refreshAcessTokenHandler = setTimeout(() => {
|
this.refreshAccessTokenHandler = setTimeout(() => {
|
||||||
this.refreshAccessToken();
|
this.refreshAccessToken();
|
||||||
}, (expires_in - 10) * 1000);
|
}, (expires_in - 10) * 1000);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue