Skip to content

Instantly share code, notes, and snippets.

@vinsonzou
Created June 11, 2021 08:12
Show Gist options
  • Select an option

  • Save vinsonzou/fa6ea86de40dd36bce5eaa4c4e936942 to your computer and use it in GitHub Desktop.

Select an option

Save vinsonzou/fa6ea86de40dd36bce5eaa4c4e936942 to your computer and use it in GitHub Desktop.
企业微信接口,示例为联系人tag调整,可以自定义任何想实现功能。
local require = require
local ngx = ngx
local http = require "resty.http" -- https://github.com/ledgetech/lua-resty-http
local wxcrypt = require "resty.crypt" -- https://github.com/vinsonzou/WXBizMsgCrypt
local xml2lua = require "xml2lua" -- https://github.com/manoelcampos/xml2lua
local handler = require "xmlhandler.tree"
local cjson = require "cjson.safe"
local ngx_re = require "ngx.re"
local json_encode = cjson.encode
local json_decode = cjson.decode
local base64_decode = ngx.decode_base64
local tconcat = table.concat
local re_find = ngx.re.find
local re_gsub = ngx.re.gsub
local corpId = "企业微信: 企业ID"
local AgentId = "企业微信: 应用-AgentId"
local Secret = "企业微信: 应用-Secret"
local Token = "企业微信: 应用-API接收消息-Token"
local EncodingAESKey = "企业微信: 应用-API接收消息-EncodingAESKey"
local AESKey = base64_decode(EncodingAESKey .. "=")
local wechat = ngx.shared.wechat
local function get_accessToken()
local accessToken, flags = wechat:get("accessToken")
if accessToken then
return accessToken
end
local url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" .. corpId .. "&corpsecret=" .. Secret
local httpc = http.new()
local res, err = httpc:request_uri(url, {
method = "GET",
keepalive_timeout = 60000,
keepalive_pool = 10
})
if res.status == 200 then
local res_body = json_decode(res.body)
if res_body.errcode == 0 then
local ok, err = wechat:set("accessToken", res_body.access_token, res_body.expires_in)
return res_body.access_token
end
end
end
local function get_tag_userlist(accessToken)
local url = "https://qyapi.weixin.qq.com/cgi-bin/tag/get?tagid=34&access_token=" .. accessToken
local httpc = http.new()
local res, err = httpc:request_uri(url, {
method = "POST",
keepalive_timeout = 60000,
keepalive_pool = 10
})
if res.status == 200 then
local res_body = json_decode(res.body)
if res_body.errcode == 0 then
local userlist = res_body["userlist"]
local userids = {}
local t = {}
local idx = 0
for _, v in pairs(userlist) do
idx = idx + 1
userids[idx] = v.userid
t[idx] = v.name
end
return userids, tconcat(t, ",")
end
end
end
local function del_tag_userlist(accessToken)
local userids, usernames = get_tag_userlist(accessToken)
if #userids == 0 then
return true
end
local url = "https://qyapi.weixin.qq.com/cgi-bin/tag/deltagusers?access_token=" .. accessToken
local httpc = http.new()
local data = {
tagid = 34,
userlist = userids,
}
local res, err = httpc:request_uri(url, {
method = "POST",
body = json_encode(data),
keepalive_timeout = 60000,
keepalive_pool = 10
})
if res.status == 200 then
local res_body = json_decode(res.body)
if res_body.errcode == 0 then
return true
end
end
end
local function update_tag_userlist(accessToken, userid)
del_tag_userlist(accessToken)
local url = "https://qyapi.weixin.qq.com/cgi-bin/tag/addtagusers?access_token=" .. accessToken
local httpc = http.new()
local data = {
tagid = 34,
userlist = {userid},
}
local res, err = httpc:request_uri(url, {
method = "POST",
body = json_encode(data),
keepalive_timeout = 60000,
keepalive_pool = 10
})
if res.status == 200 then
local res_body = json_decode(res.body)
if res_body.errcode == 0 then
return true
else
return false
end
end
end
local method = ngx.req.get_method()
local headers = ngx.req.get_headers()
local args = ngx.req.get_uri_args()
local msg_signature = args.msg_signature
local timestamp = args.timestamp
local nonce = args.nonce
local echostr = args.echostr
local msg_encrypt
if method == "GET" and echostr then
local TmpStr = ngx.unescape_uri(echostr)
-- ngx_lua会将GET请求参数的"+" 转换为 " "
-- ngx_lua会将GET请求参数的"=" 转换为 ":"
local encode_str, n, err = re_gsub(TmpStr, [[ ]], "+", "jo")
msg_encrypt = encode_str
elseif method == "POST" then
ngx.req.read_body()
local body_data = ngx.req.get_body_data()
local parser = xml2lua.parser(handler)
parser:parse(body_data)
for i, p in pairs(handler.root) do
msg_encrypt = p.Encrypt
end
end
local signature = wxcrypt:get_sha1({Token, timestamp, nonce, msg_encrypt})
if signature == msg_signature then
local wxmc = wxcrypt:new(Token, EncodingAESKey, corpId)
local msg = wxmc:decrypt(msg_encrypt)
if method == "POST" then
local EventKey, UserName, CustomAction
local parser = xml2lua.parser(handler)
parser:parse(msg)
for i, p in pairs(handler.root) do
local MsgType = p.MsgType
UserName = p.FromUserName
if MsgType == "event" then
EventKey = p.EventKey
elseif MsgType == "text" then
CustomAction = p.Content
end
end
local ReplyMsg = {
ToUserName = UserName,
FromUserName = corpId,
CreateTime = ngx.time(),
MsgType = "text",
AgentID = AgentId,
}
if EventKey then
if EventKey == "onduty_now" then
local accessToken = get_accessToken()
local userids, usernames = get_tag_userlist(accessToken)
ReplyMsg["Content"] = usernames
local ReplyMsg_xml = xml2lua.toXml(ReplyMsg, "xml")
local encrypted = wxmc:encrypt(ReplyMsg_xml, timestamp, nonce)
ngx.say(encrypted)
elseif re_find(EventKey, [[^onduty_(zhangsan|lisi|wangwu)$]], "jo") then
local result, err = ngx_re.split(EventKey, "_")
local userid = result[2]
local accessToken = get_accessToken()
if update_tag_userlist(accessToken, userid) then
ReplyMsg["Content"] = "当前值班调整为" .. userid
else
ReplyMsg["Content"] = "[异常]当前值班调整为" .. userid
end
local ReplyMsg_xml = xml2lua.toXml(ReplyMsg, "xml")
local encrypted = wxmc:encrypt(ReplyMsg_xml, timestamp, nonce)
ngx.say(encrypted)
end
end
elseif method == "GET" then
ngx.say(msg)
end
end
@vinsonzou
Copy link
Author

nginx vhost.conf如下:

lua_shared_dict wechat 1m;

server {
    listen 443 ssl http2;
    ssl_certificate     test.crt;
    ssl_certificate_key test.key;
    ssl_protocols             TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
    ssl_session_timeout       1d;
    ssl_session_cache         shared:SSL:20m;
    add_header Strict-Transport-Security max-age=31536000;
    server_name wx-ops.test.com;
    access_log logs/wechat-ops.access.log main;
    error_log logs/wechat-ops.info;

    location /api/ {
        resolver local=on ipv6=off;
        resolver_timeout 2s;
        lua_ssl_verify_depth 1;
        lua_ssl_trusted_certificate /etc/pki/tls/certs/ca-bundle.crt;
        content_by_lua_file lua/wechat-ops.lua;
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment