Lua で書かれた nginx サーバー WeChat パブリック プラットフォーム エージェントを使用します。
ターゲット:
フロントエンド nginx を WeChat プロキシとして使用して、内部アプリケーション層と WeChat サービス間の結合を軽減します。
WeChat パブリック アカウントの自動応答を構成し、一部のユーザー メッセージを nginx で処理して、アプリケーション層への負担を軽減します。
WeChat パブリック アカウント API で使用されるaccess_token
を一元管理し、ビジネス層と API 実装を分離する中央制御サーバーとして使用し、 access_token
競合率を減らし、サービスの安定性を高めます。
WeChat JS-SDK 認証コールバック ページをデプロイして、アプリケーション層への負担を軽減します。
構成
インターフェイス トークンや自動応答設定を含む、パブリック アカウントのグローバル構成データ。
サーバ
WeChat からの通常のメッセージおよびイベント プッシュ リクエストを受信し、設定に従って応答します。対応する設定が行われていない場合は、WeChat の要件に従ってsuccess
が返されます。
コア コードのこの部分は、aCayF/lua-resty-wechat からリファクタリングおよび変更されています。
config.autoreplyurl
使用して、バックグラウンド処理サービスのアドレスを構成し、複雑な WeChat メッセージを転送、処理、および応答します (pintsize/lua-resty-http に応じて)。
プロキシアクセストークン
Redis を使用してaccess_token
とjsapi_ticket
キャッシュし、WeChat サービスの更新を定期的に自動的に呼び出し、分散更新をサポートします。
プロキシ
エージェントは WeChat パブリック プラットフォーム API インターフェイスを呼び出し、 access_token
パラメーターを自動的に追加します。
プロキシアクセスフィルター
クライアント IP をフィルターし、リクエスト ソースを制限します。
認証
jssdk_config
nginxの設定:
http { lua_package_path 'lua ファイルへのパス';solver 114.114.114.114; lua_shared_dict wechat 1M; # 共有メモリを使用して単一のタイマーを維持する init_by_lua ' ngx.shared.wechat:delete("updater") -- タイマー識別子をクリアします"resty.wechat.config") '; init_worker_by_lua ' ローカル ok、err = ngx.shared.wechat:add("updater", "1") -- 単一プロセスの起動タイマー、ok またはエラーでない場合は return end require("resty.wechat.proxy_access_token")() ' ; サーバー {location /wechat-server { content_by_lua ' require("resty.wechat.server")() '; }location /wechat-proxy/ { rewrite_by_lua ' require("resty.wechat.proxy")("wechat-proxy") -- パラメータは場所のパスです'; access_by_lua ' require("resty.wechat.proxy_access_filter")( ) ' ; プロキシパス https://api.weixin.qq.com/; }location /wechat-baseoauth { # param: goto rewrite_by_lua ' require("resty.wechat.oauth").base_oauth("path to /wechat-redirect") '; }location /wechat-useroauth { # param: goto rewrite_by_lua ' require("resty.wechat.oauth").userinfo_oauth("path to /wechat-redirect") '; }location /wechat-redirect { rewrite_by_lua ' require("resty.wechat.oauth").redirect() '; }location /wechat-jssdk-config { # GET/POST, param: url, [api] add_header Access-Control-Allow-Origin "クロスドメイン呼び出しが必要な場合"; require("resty.wechat.jssdk_config") () '; } } }
Web ページ挿入 JS-SDK 権限:
$.ajax({ URL: "/wechat-jssdk-config への URL パス", データ: {url: window.location.href,api: "onMenuShareTimeline|onMenuShareAppMessage|onMenuShareQQ|onMenuShareWeibo|onMenuShareQZone" }、 成功: function(response) {wx.config(response); }});$.ajax({ URL: "/wechat-jssdk-config への URL パス", データ: {url: window.location.href }、 success: function(response) {wx.config({ appId:response.appId, timestamp:response.timestamp,nonceStr:response.nonceStr,signature:response.signature, jsApiList:[ 'onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ' 、 'onMenuShareWeibo'、 'onMenuShareQZone' ]}); }});
Java を使用して、プロキシ Web ページ認証によって取得された Cookie を解析する
Map authInfo = JSON.parseObject(decryptAES(unBase64("cookie value"), getKey("AES key")));//デフォルトの AES キー: "vFrItmxI9ct8JbAg"//config.lua で設定 -> cookie_aes_key//Dependency メソッドインポート com.alibaba.fastjson.JSON;インポートcom.google.common.base.Charsets;import javax.crypto.Cipher;import javax.crypto.spec.SecretKeySpec;import java.security.Key;public StringBuilder のパディング(String s, char 文字, int の繰り返し) {StringBuilder sb = new StringBuilder(s); while (repeats-- > 0) {sb.append(letter); }sbを返します。 } public String padding(String s) {return padding(s, '=', s.length() % 4).toString(); }public byte[] unBase64(String value) {return org.apache.commons.codec.binary.Base64.decodeBase64(padding(value)); } public String string(byte[] bytes) {return new String(bytes, Charsets.UTF_8); }public String decryptAES(byte[] value, Key key) {try {Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");cipher.init(Cipher.DECRYPT_MODE, key);byte[] 復号化 = cipher。 doFinal(値);文字列を返します(復号化); catch (Exception e) {throw new RuntimeException(e); } }public byte[] bytes(String str) {return str == null ? null : str.getBytes(Charsets.UTF_8); }公開キー keyFromString(String keyString) {return new SecretKeySpec(bytes(keyString), "AES"); }公開キー getKey(String key) {if (key.length() >= 16) {return keyFromString(key.substring(0, 16)); }StringBuilder sb = new StringBuilder(key);while (sb.length() < 16) {sb.append(key); }return keyFromString(sb.toString().substring(0, 16)); }