123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- /**
- * @Author HonorLee (dev@honorlee.me)
- * @Version 2.0 (2019-10-08)
- */
- // 'use strict'
- //基础配置项
- import { RedisClientType } from '@redis/client';
- import sha1 from 'sha1'
- import wxerr from '../errcodes'
- // eslint-disable-next-line @typescript-eslint/no-var-requires
- // const random = require('string-random')
- const errMsg:AnyKeyString = wxerr;
- const randomStr = (length?:number,nonum?:boolean)=>{
- let arr = '1234567890abcdefghijklmnopqrstuvwxyz';
- if(nonum) arr = 'abcdefghijklmnopqrstuvwxyz';
- let str = '';
- length = length?length:3;
- for(let i = 0;i<length;i++){
- str += arr.substr(Math.floor(Math.random()*26),1);
- }
- return str;
- }
- const WechatDomain = `https://api.weixin.qq.com`;
- class WechatSDK{
- private _redisClient:RedisClientType;
- private _appId;
- private _token;
- private _appSecret;
- private _aesKey;
- private _wechatApiURL
- public constructor(redisInstance:RedisClientType,options:{appId:string,token:string,appSecret:string,aesKey:string}) {
- this._redisClient = redisInstance;
- this._appId = options.appId;
- this._token = options.token;
- this._appSecret = options.appSecret;
- this._aesKey = options.aesKey;
- this._wechatApiURL = {
- getAccessToken:`${WechatDomain}/cgi-bin/token?grant_type=client_credential&appid=${this._appId}&secret=${this._appSecret}`,
- getJsApiTicket:`${WechatDomain}/cgi-bin/ticket/getticket?type=jsapi&access_token=`,
- getJsOauthCode:`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${this._appId}`,
- getOauthToken:`${WechatDomain}/sns/oauth2/access_token?appid=${this._appId}&secret=${this._appSecret}&grant_type=authorization_code`,
- getOauthUserinfo:`${WechatDomain}/sns/userinfo?lang=zh_CN`,
- getCode2Session:`${WechatDomain}/sns/jscode2session?appid=${this._appId}&secret=${this._appSecret}&grant_type=authorization_code&js_code=`
- }
- }
- //验签
- public checkSignature(signature:string,timestamp:string|number,nonce:string){
- const arr = [this._token, timestamp, nonce];
- arr.sort();
- return sha1(arr.join('')) === signature;
- }
- public getAccessToken(){
- return new Promise(async (resolve,reject)=>{
- const token = await this._redisClient.get(`WECHAT_${this._appId}_ACCESSTOKEN`);
- console.log(!!token)
- if(token) return resolve({token});
- //请求新的Token
- LOGGER.debug('[Wechat] Get new token')
- REQUEST({url:this._wechatApiURL.getAccessToken,encoding:'UTF-8',json:true},async (err:any,response:any,body:any)=>{
- if(err || !body){
- LOGGER.error('Wechat getAccessToken error!');
- LOGGER.error(err.stack);
- return resolve({err:new Error('Wechat getAccessToken error!')});
- }
- if(body.errcode){
- LOGGER.debug(body.errmsg||'body.errcode');
- return resolve({err:new Error(`ERROR_CODE:${errMsg[body.errcode]}`)});
- }
- const _token = body.access_token;
- const expires = body.expires_in - 5 * 60;
- await this._redisClient.set(`WECHAT_${this._appId}_ACCESSTOKEN`,_token,{EX:expires});
- resolve({token:_token});
- });
-
- });
- }
- public async getJsApiTicket(){
- const token:any = await this.getAccessToken();
- if(token.err) return token;
- return new Promise(async (resolve,reject)=>{
- const ticket = await this._redisClient.get(`WECHAT_${this._appId}_JSAPITICKET`);
- if(ticket) return resolve({ticket});
- REQUEST({url:`${this._wechatApiURL.getJsApiTicket}${token.token}`,encoding:'UTF-8',json:true},(err:any,response:any,body:any)=>{
- if(err || !body){
- LOGGER.error('Wechat getJsApiTicket error!');
- LOGGER.error(err.stack);
- return resolve({err:new Error('Wechat getJsApiTicket error!')});
- }
- if(body.errcode){
- return resolve({err:new Error(`ERROR_CODE:${errMsg[body.errcode]}`)});
- }
- const _ticket = body.ticket;
- const expires = body.expires_in - 5;
- this._redisClient.set(`WECHAT_${this._appId}_JSAPITICKET`,_ticket,{EX:expires});
- resolve({ticket:_ticket});
- })
- });
- }
- public async getSignature(url:string){
- if(!url) return {err:new Error('URL is empty!')};
- const noncestr = randomStr(16);
- const timestamp = Math.floor(new Date().getTime());
- const ticket = await this.getJsApiTicket();
- const combineStr = `jsapi_ticket=${ticket.ticket}&noncestr=${noncestr}×tamp=${timestamp}&url=${url}`;
- const signature = sha1(combineStr);
- return {nonceStr:noncestr,timestamp:timestamp,signature:signature,appId:this._appId};
- }
- public getJsOauthCodeURL(redirectURL:string,Scope:string,State?:string){
- if(!redirectURL || !redirectURL.match(/(https?):\/\/[-A-Za-z0-9+&@#\/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]/gi)){
- return {err:new Error('redirectURL Error')};
- }
- if(Scope!='snsapi_base' && Scope!='snsapi_userinfo'){
- return {err:new Error('Scope must be snsapi_base or snsapi_userinfo')};
- }
- if(!State) State = 'null';
- redirectURL = encodeURI(redirectURL);
- const urlString = `${this._wechatApiURL.getJsOauthCode}&redirect_uri=${redirectURL}&response_type=code&scope=${Scope}&state=${State}#wechat_redirect`;
- return {url:urlString};
- }
- public async getOauthToken(code:string){
- if(!code) return {err:new Error('Code is empty!')};
- return new Promise((resolve,reject)=>{
- REQUEST({url:`${this._wechatApiURL.getOauthToken}&code=${code}`,encoding:'UTF-8',json:true},(err:any,response:any,body:any)=>{
- if(err || !body){
- LOGGER.error('Wechat getOauthToken error!');
- LOGGER.error(err.stack);
- return resolve({err:new Error('Wechat getOauthToken error!')});
- }
- if(body.errcode){
- return resolve({err:new Error(`ERROR_CODE:${errMsg[body.errcode]}`)});
- }
- resolve({token:body.access_token,openid:body.openid});
- });
- })
- }
- public getOauthUserinfo(oAuthToken:string,openid:string){
- return new Promise((resolve,reject)=>{
- REQUEST({url:`${this._wechatApiURL.getOauthUserinfo}&access_token=${oAuthToken}&openid=${openid}`,encoding:'UTF-8',json:true},(err:any,response:any,body:any)=>{
- if(err || !body){
- LOGGER.error('Wechat getOauthUserinfo error!');
- LOGGER.error(err.stack);
- return resolve({err:new Error('Wechat getOauthUserinfo error!')});
- }
- if(body.errcode){
- return resolve({err:new Error(`ERROR_CODE:${errMsg[body.errcode]}`)});
- }
- resolve({userinfo:body});
- });
- })
- }
- public async getOauthUserinfoByCode(code:string){
- const _authToken = await this.getOauthToken(code) as AnyKeyString;
- if(_authToken && !_authToken.err){
- const _userInfo = await this.getOauthUserinfo(_authToken.access_token,_authToken.openid);
- return _userInfo;
- }else{
- return null;
- }
- }
- public getCodeSession(code:string){
- return new Promise((resolve,reject)=>{
- REQUEST({url:`${this._wechatApiURL.getCode2Session}${code}`,encoding:'UTF-8',json:true},(err:any,response:any,body:any)=>{
- // console.log(1,err,response,body)
- if(err || !body){
- LOGGER.error('Wechat getCode2Session error!');
- LOGGER.error(err.stack);
- return resolve({err:new Error('Wechat getCode2Session error!')});
- }
- if(body.errcode){
- return resolve({err:new Error(`ERROR_CODE:${body.errcode} - ${errMsg[body.errcode]}`)});
- }
- resolve({openid:body.openid,unionid:body.unionid,session_key:body.session_key});
- });
- })
- }
- }
- module.exports = WechatSDK;
|