微信鉴权环境的内网部署方案

本文适用范围:
一、微信开发相关业务,涉及到微信第三方开发者鉴权、公众号鉴权业务;
二、没有固定IP的内网部署环境,尤其是测试环境。IP经常变动,导致鉴权失效。
三、本文写作时尚未解决主动定时拉取token的问题(跳板机的正向代理)

开放平台主动推送ticket到内网的解决办法

解决方案核心思路:
使用带有固定IP的外网服务器,此处称:跳板服务器,作为内网服务器的端口转发服务器。和鉴权有关的域名解析到该服务器。
使用到的工具为nginx,具体的操作自己百度。
脚本实现:
1、内网一个服务器定时,30分钟获取一次外部IP地址,推送到跳板服务器的文本当中;

1
2
3
4
5
6
#!/bin/bash
#设置环境变量
source /etc/profile
curl http:\/\/www.baidu.com\/s?wd\=ip|grep "本机IP"|awk -F "</span>" '{print $1}'|awk -F ";" '{print $2}' > ip.txt
ip_local=`cat ip.txt`
sshpass -p ${PASSWORD} ssh -p ${PORT}-tt root@IP "echo ${ip_local} > ip.txt"

获取本地IP的方法不止一种,我提供的是最复杂的。
2、跳板服务器定时任务,30分钟获取一次文本中IP地址情况,同nginx中的配置进行比较,不相等则批量替换IP地址后reload配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash
#设置环境变量
source /etc/profile
newIP=`sed -n 1p /home/user/ip.txt`
echo ${newIP}
temp_old_IP=`grep proxy_pass /etc/nginx/conf.d/mk.conf |tail -n 1|awk -F ':' '{print $2}'`
#echo $temp_old_IP
old_IP=${temp_old_IP:2:${#temp_old_IP}}
#echo ${old_IP}
if [[ ${newIP} != ${old_IP} ]] && [[ -n ${newIP} ]]
then
sed -i "s/${old_IP}/${newIP}/g" /etc/nginx/conf.d/mk-internal-T*conf
<!-- more -->
cd /usr/sbin/
./nginx -s reload
echo `date` 'New IP: ' ${newIP} >> /home/user/ip_logs.log
else
echo `date` 'IP No Change: ' ${old_IP} >> /home/user/ip_logs.log
fi

需要注意的是:
1、内网路由器需支持虚拟服务器的配置,将路由器的外网端口映射给内网服务器。
2、使用nginx的跳板服务器,需要定时获取到公司外部的IP地址变化,如发生变化则reload nginx的服务。我写了一个shell脚本,在内部测试服务器上运行,30分钟侦测一次外网IP,并将IP输入到跳板服务器上。跳板服务器,也定时去取这个IP并和nginx内的IP对比,不等就替换reload。
3、内网服务器也可以部署nginx再转一次,做到内网一个端口多次使用,前提是跳板服务器过去的请求带上域名。
4、如果链接带https,这个方案也是可行的。这里有一个坑,一般tomcat部署https,会把tomcat服务器端口在配置中redirect给443端口。这时候,就需要把这个redirect从tomcat配置中移走,让firewall去转发,否则从跳板过来的请求,会陷入死循环的redirect。(跳版443端口接收到请求,redirect给内网的外网IP—->映射给内网的tomcat端口—->redirect给tomcat的端口,如果tomcat再redirect给443,则会回到链路请求的开始,直到达到请求的限制次数)。

内网主动拉取token设置IP白名单的问题

最合理的解决方案自然是最底层的,服务器请求https://open.weixin.qq.com/的数据包走代理服务器(拥有固定IP),但是这种办法只是理论上,我们技术团队目前并没有找到具体如何操作(限于透出产出比较低)。
我基于能力范围,找到IP变动导致的微信开放平台手动添加白名单的替代方法。
思路:webdriver驱动浏览器,自动录入ip白名单。
实现代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# -*- coding: utf-8 -*-
# chromedriver同级目录下
from splinter import Browser
import datetime, time
from urllib2 import urlopen
import schedule

def changIP(ip):
browser = Browser('chrome', )
browser.driver.set_window_size(1600, 1000)
browser.visit("https://open.weixin.qq.com/")
browser.find_by_id("loginBarBt").click()
browser.find_by_name("account").fill(u"${account}")
browser.find_by_name("passwd").fill(u"${password}")
browser.find_by_text("登录")[2].click()

# MK内网T6
browser.find_by_xpath("//*[@data-param='appid=wxfb1fb56deb2664a8']").click()
time.sleep(2)
browser.windows.current = browser.windows[1]
n = 200
while True:
browser.evaluate_script('window.scrollTo(0,%d)' % n)
if browser.is_element_present_by_id('js_fastmodify_ip'):
break

browser.find_by_id('js_fastmodify_ip').first.click()
time.sleep(1)
browser.find_by_xpath("/html/body/div[6]/div/div[2]/textarea").fill(u"%s" % ip)
browser.find_by_text('确定').click()
time.sleep(2)
# 关闭当前标签页
browser.driver.close()
browser.windows.current = browser.windows[0]

# 退出浏览器
browser.quit()
#定时任务
def job():
new_ip = urlopen('http://ip.42.pl/raw').read()
f = open('local_IP.txt', 'r')
old_ip_line = f.readlines()
f.close()
# 日志
log = open('local_IP_log.txt', 'a')
logtime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
for ip in old_ip_line:
old_ip = ip

if new_ip != old_ip:
logs=logtime+"=== IP change to " + new_ip + '\n'
log.write(logs)
log.close()
f = open('local_IP.txt', 'w')
f.write(new_ip)
f.close()
changIP(new_ip)
else:
logs=logtime+"=== IP do not change " + '\n'
log.write(logs)
log.close()
if __name__ == '__main__':
schedule.every(15).minutes.do(job)
while True:
schedule.run_pending()
time.sleep(300)

代码示意,实际上我们内网维护了大概有4个公共平台,改四次,还是蛮划算的。