ใช้ตัวแทนแพลตฟอร์มสาธารณะ WeChat ของเซิร์ฟเวอร์ nginx ที่เขียนด้วยภาษา Lua
เป้า:
ใช้ nginx ส่วนหน้าเป็นพร็อกซี WeChat เพื่อลดการเชื่อมโยงระหว่างเลเยอร์แอปพลิเคชันภายในและบริการ WeChat
กำหนดค่าการตอบกลับอัตโนมัติสำหรับบัญชีสาธารณะ WeChat และประมวลผลข้อความของผู้ใช้บางส่วนใน nginx เพื่อลดแรงกดดันต่อเลเยอร์แอปพลิเคชัน
การจัดการแบบรวมศูนย์ของ access_token
ที่ใช้ใน API บัญชีสาธารณะ WeChat ในฐานะเซิร์ฟเวอร์ควบคุมส่วนกลางเพื่อแยกชั้นธุรกิจและการใช้งาน API ช่วยลดอัตราข้อขัดแย้ง 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 โดยอัตโนมัติเป็นประจำ และรองรับการอัปเดตแบบกระจาย
พร็อกซี
ตัวแทนเรียกใช้อินเทอร์เฟซ API แพลตฟอร์มสาธารณะ WeChat และเพิ่มพารามิเตอร์ access_token
โดยอัตโนมัติ
proxy_access_filter
กรอง IP ไคลเอ็นต์และจำกัดแหล่งที่มาของคำขอ
คำสาบาน
jssdk_config.jssdk_config
การกำหนดค่า nginx:
http { lua_package_path 'path to lua files'; 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 ' local ok, err = ngx.shared.wechat:add("updater", "1") -- ตัวจับเวลาการเริ่มต้นกระบวนการเดี่ยว หากไม่โอเคหรือผิดพลาด ให้ส่งคืน end need("resty.wechat.proxy_access_token")() ' ; เซิร์ฟเวอร์ {location /wechat-server { content_by_lua ' need("resty.wechat.server")() - }location /wechat-proxy/ { rewrite_by_lua ' need("resty.wechat.proxy")("wechat-proxy") -- พารามิเตอร์คือพาธของตำแหน่ง'; access_by_lua ' need("resty.wechat.proxy_access_filter")( ) ' ; proxy_pass https://api.weixin.qq.com/; }location /wechat-baseoauth { # param: goto rewrite_by_lua ' need("resty.wechat.oauth").base_oauth("path to /wechat-redirect") '; }location /wechat-useroauth { # param: goto rewrite_by_lua ' need("resty.wechat.oauth").userinfo_oauth("path to /wechat-redirect") '; } ตำแหน่ง /wechat-redirect { rewrite_by_lua ' need("resty.wechat.oauth").redirect() '; }location /wechat-jssdk-config { # GET/POST, param: url, [api] add_header Access-Control-Allow-Origin "หากจำเป็นต้องเรียกข้ามโดเมน"; () '; - - -
สิทธิ์การแทรกหน้าเว็บ JS-SDK:
$.ajax({ 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 เพื่อแยกวิเคราะห์คุกกี้ที่ได้รับจากการอนุญาตหน้าเว็บพร็อกซี
แผนที่ authInfo = JSON.parseObject(decryptAES(unBase64("cookie value"), getKey("AES key")));//คีย์ AES เริ่มต้น: "vFrItmxI9ct8JbAg"//กำหนดค่าใน config.lua -> cookie_aes_key//วิธีการพึ่งพา นำเข้า com.alibaba.fastjson.JSON;นำเข้า com.google.common.base.Charsets;นำเข้า javax.crypto.Cipher;นำเข้า javax.crypto.spec.SecretKeySpec;นำเข้า java.security.Key;การขยาย StringBuilder สาธารณะ (สตริง s, ตัวอักษรถ่าน, int ซ้ำ) {StringBuilder sb = ใหม่ StringBuilder(s); while (ซ้ำ-- > 0) {sb.append(ตัวอักษร); } กลับ sb; } การขยายสตริงสาธารณะ (สตริง s) { ส่งคืนการขยาย (s, '=', s.length() % 4).toString(); } ไบต์สาธารณะ [] unBase64 (ค่าสตริง) {return org.apache.commons.codec.binary.Base64.decodeBase64 (ช่องว่างภายใน (ค่า)); } สตริงสตริงสาธารณะ (ไบต์ [] ไบต์) { คืนสตริงใหม่ (ไบต์, Charsets.UTF_8); }สตริงสาธารณะ decryptAES(ค่าไบต์[], คีย์คีย์) {ลอง {Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");cipher.init(Cipher.DECRYPT_MODE, key);byte[] ถอดรหัส = cipher doFinal (ค่า); สตริงส่งคืน (ถอดรหัสแล้ว); } catch (ข้อยกเว้น e) { โยน RuntimeException ใหม่ (e); - } ไบต์สาธารณะ [] ไบต์ (String str) {return str == null ? : str.getBytes (Charsets.UTF_8); } คีย์สาธารณะ keyFromString (String keyString) { คืน SecretKeySpec ใหม่ (ไบต์ (keyString), "AES"); } คีย์สาธารณะ getKey (คีย์สตริง) {if (key.length() >= 16) {return keyFromString(key.substring(0, 16)); }StringBuilder sb = new StringBuilder(คีย์);ในขณะที่ (sb.length() < 16) {sb.append(คีย์); } return keyFromString(sb.toString().substring(0, 16)); -