استخدم وكيل منصة WeChat العامة لخادم nginx المكتوب بلغة Lua.
هدف:
استخدم nginx للواجهة الأمامية كوكيل WeChat لتقليل الاقتران بين طبقة التطبيق الداخلية وخدمات WeChat.
قم بتكوين الردود التلقائية لحسابات WeChat العامة ومعالجة بعض رسائل المستخدم في nginx لتقليل الضغط على طبقة التطبيق.
الإدارة الموحدة لـ access_token
المستخدمة في واجهة برمجة تطبيقات حساب WeChat العام، كخادم تحكم مركزي لعزل طبقة الأعمال وتنفيذ واجهة برمجة التطبيقات، وتقليل معدل تعارض access_token
وزيادة استقرار الخدمة.
انشر صفحة رد اتصال ترخيص WeChat JS-SDK لتقليل الضغط على طبقة التطبيق.
التكوين
بيانات التكوين العامة للحساب العام، بما في ذلك الرمز المميز للواجهة وإعدادات الرد التلقائي.
الخادم
تلقي طلبات الرسائل العادية وطلبات دفع الأحداث من WeChat، والرد وفقًا للتكوين. إذا لم يتم إجراء تكوين مطابق، فسيتم إرجاع success
وفقًا لمتطلبات WeChat.
تمت إعادة هيكلة هذا الجزء من الكود الأساسي وتعديله من aCayF/lua-resty-wechat.
استخدم config.autoreplyurl
لتكوين عنوان خدمة معالجة الخلفية، وإعادة توجيه رسائل WeChat المعقدة ومعالجتها والرد عليها (يعتمد على حجم pintsize/lua-resty-http).
proxy_access_token
استخدم Redis لتخزين access_token
و jsapi_ticket
مؤقتًا، واستدعاء تحديثات خدمة WeChat تلقائيًا بانتظام، ودعم التحديثات الموزعة.
الوكيل
يستدعي الوكيل واجهة WeChat العامة لواجهة برمجة التطبيقات (API) ويضيف تلقائيًا معلمة access_token
.
proxy_access_filter
تصفية عنوان IP للعميل والحد من مصادر الطلب.
com.auth
jssdk_config
تكوين نجينكس:
http { lua_package_path 'path to lua files'; "resty.wechat.config") '; init_worker_by_lua ' حسنًا محليًا، err = ngx.shared.wechat:add("updater"، "1") - مؤقت بدء تشغيل عملية واحدة إذا لم يكن جيدًا أو أخطأ، فارجع 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")( ) '؛ proxy_pass 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-userauth { # 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 "إذا كنت بحاجة إلى اتصال عبر المجال" content_by_lua ' require("resty.wechat.jssdk_config"); () '؛ } } }
أذونات حقن صفحة الويب JS-SDK:
$.اجاكس({ URL: "مسار URL إلى /wechat-jssdk-config"، البيانات: {url: window.location.href,api: "onMenuShareTimeline|onMenuShareAppMessage|onMenuShareQQ|onMenuShareWeibo|onMenuShareQZone" }, النجاح: الوظيفة (الاستجابة) {wx.config (الاستجابة)؛ }});$.ajax({ URL: "مسار URL إلى /wechat-jssdk-config"، البيانات: {عنوان URL: window.location.href }, النجاح: الوظيفة (الاستجابة) {wx.config({ appId: Response.appId، الطابع الزمني: Response.timestamp، nonceStr: Response.nonceStr، التوقيع: Response.signature، jsApiList: [ 'onMenuShareTimeline'، 'onMenuShareAppMessage'، 'onMenuShareQQ' , 'onMenuShareWeibo', 'onMenuShareQZone' ]}); }});
استخدم Java لتحليل ملفات تعريف الارتباط التي تم الحصول عليها عن طريق ترخيص صفحة ويب الوكيل
Map authInfo = JSON.parseObject(decryptAES(unBase64("cookie value"), getKey("AES key")));// مفتاح AES الافتراضي: "vFrItmxI9ct8JbAg"// تم تكوينه في config.lua -> cookie_aes_key// طريقة التبعية import com.alibaba.fastjson.JSON;import com.google.common.base.Charsets;import javax.crypto.Cipher;import javax.crypto.spec.SecretKeySpec;import java.security.Key;public StringBuilder padding(String s, char letter, int Repeats) {StringBuilder sb = new StringBuilder(s); while (repeats--> 0) {sb.append(letter); }إرجاع بينالي الشارقة؛ } public String padding(String s) {return padding(s, '=', s. length() % 4).toString(); }البايت العام[] unBase64(قيمة السلسلة) {return org.apache.commons.codec.binary.Base64.decodeBase64(padding(value)); }سلسلة سلسلة عامة (بايت[] بايت) {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[] decrypted = cipher. doFinal(value);سلسلة الإرجاع(فك تشفيرها); } Catch (Exception e) {throw new RuntimeException(e); } } البايت العام [] بايت (سلسلة str) {return str == 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)); }