| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286 |
- local http = require("fwutils.httpclient")
- local codec = require("fastweb.codec")
- local base64 = require("fwutils.base64")
- local openssl = require("openssl")
- local M = {}
- local url_get_access_token = "https://qyapi.weixin.qq.com/cgi-bin/gettoken"
- local url_send_message = "https://qyapi.weixin.qq.com/cgi-bin/message/send"
- local url_get_userid_by_mobile = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserid"
- local url_get_userids = "https://qyapi.weixin.qq.com/cgi-bin/user/list_id"
- -- 验证签名
- M.verify_signature = function(token,timestamp,nonce,echostr)
- local params = {token, timestamp, nonce, echostr}
- table.sort(params, function(a, b) return tostring(a) < tostring(b) end)
- return string.lower(codec.sha1(table.concat(params)))
- end
- -- 解密数据
- M.decrypt_data = function(qywx_aeskey,data)
- -- 16随机数+4字节消息长度+消息体+接收ID
- local function parse_decrypted_msg(data)
- -- data: string, decrypted_echostr
- if #data < 20 then
- return nil, "data too short"
- end
- -- 跳过16字节随机数
- local msg_len_bytes = data:sub(17, 20)
- local b1, b2, b3, b4 = msg_len_bytes:byte(1, 4)
- local msg_len = b1 * 2^24 + b2 * 2^16 + b3 * 2^8 + b4
- local msg_start = 21
- local msg_end = 20 + msg_len
- local msg = data:sub(msg_start, msg_end)
- return msg
- end
-
- local cipher = openssl.cipher.new("aes-256-cbc")
- cipher:init(base64.decode(qywx_aeskey), "0123456789abcdef", false)
- local plaintext = cipher:update(data)
- plaintext = parse_decrypted_msg(plaintext)
- return plaintext
- end
- -- 获取access_token
- M.get_access_token = function(corpid,corpsecret)
- local url = url_get_access_token .. "?corpid=" .. corpid .. "&corpsecret=" .. corpsecret
- local result,err = http.get(url,{
- ["Content-Type"] = "application/json"
- })
- if not result then
- return false,err
- end
- local data = cjson.decode(err)
- if data.errcode == 0 then
- return true,data.access_token
- end
- return false,data.errmsg
- end
- -- 获取userid
- M.get_userid_by_mobile = function(access_token,mobile)
- local url = url_get_userid_by_mobile .. "?access_token=" .. access_token .. "&mobile=" .. mobile
- local result,err = http.post(url,{
- ["Content-Type"] = "application/json"
- },cjson.encode({
- mobile = mobile
- }))
- if not result then
- return false,err
- end
- local data = cjson.decode(err)
- if data.errcode == 0 then
- return true,data.userid
- end
- return false,data.errmsg
- end
- -- 获取用户列表
- M.get_userids = function(access_token)
- local url = url_get_userids .. "?access_token=" .. access_token
- local result,err = http.post(url,{
- ["Content-Type"] = "application/json"
- },cjson.encode({
- limit = 1000
- }))
- if not result then
- return false,err
- end
- local data = cjson.decode(err)
- if data.errcode == 0 then
- return true,data.dept_user
- end
- return false,data.errmsg
- end
- -- 上传临时文件
- M.upload_temp_file = function(access_token,data,type_str)
- local function make_upload_temp_data(data)
- local boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW"
- local body = ""
-
- local filename = ""
- if type_str == "image" then
- filename = tostring(os.time())..".png"
- elseif type_str == "video" then
- filename = tostring(os.time())..".mp4"
- end
- -- 构造 multipart 数据
- body = body .. "--" .. boundary .. "\r\n"
- body = body .. "Content-Disposition: form-data; name=\"media\"; filename=\""..filename.."\"\r\n"
- body = body .. "Content-Type: application/octet-stream\r\n\r\n" .. data .. "\r\n"
- body = body .. "--" .. boundary .. "--\r\n"
-
- return body
- end
- local body = make_upload_temp_data(data)
- local url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token=" .. access_token.."&type="..type_str
- local result,err = http.post(url,{
- ["Content-Type"] = "multipart/form-data; boundary=--WebKitFormBoundary7MA4YWxkTrZu0gW",
- ["Content-Length"] = #body
- },body)
- if not result then
- return false,err
- end
- local data = cjson.decode(err)
- if data.errcode == 0 then
- return true,data.media_id
- end
- return false,data.errmsg
- end
- -- 发送消息
- M.send_message = function(access_token,userid,agentid,message)
- local url = url_send_message .. "?access_token=" .. access_token
- local result,err = http.post(url,{
- ["Content-Type"] = "application/json"
- },cjson.encode({
- touser = userid,
- msgtype = "text",
- agentid = agentid,
- text = {
- content = message
- }
- }))
- if not result then
- return false,err
- end
- local data = cjson.decode(err)
- if data.errcode == 0 then
- return true
- end
- return false,data.errmsg
- end
- -- 发送图片消息
- M.send_image_message = function(access_token,userid,agentid,image_filepath)
- local file = io.open(image_filepath, "rb")
- if not file then
- return false, "cannot open file: " .. tostring(image_filepath)
- end
- local data = file:read("*a")
- file:close()
- local ok, media_id = M.upload_temp_file(access_token, data,"image")
- if not ok then
- return false, "upload_temp_file_failed:"..media_id
- end
- local url = url_send_message .. "?access_token=" .. access_token
- local result, err = http.post(url, {
- ["Content-Type"] = "application/json"
- }, cjson.encode({
- touser = userid,
- msgtype = "image",
- agentid = agentid,
- image = {
- media_id = media_id,
- }
- }))
- if not result then
- return false, err
- end
- local resp = cjson.decode(err)
- if resp.errcode == 0 then
- return true
- end
- return false, resp.errmsg
- end
- -- 发送视频消息
- M.send_video_message = function(access_token,userid,agentid,title,video_filepath)
- local file = io.open(video_filepath, "rb")
- if not file then
- return false, "cannot open file: " .. tostring(video_filepath)
- end
- local data = file:read("*a")
- file:close()
- local ok, media_id = M.upload_temp_file(access_token, data,"video")
- if not ok then
- return false, "upload_temp_file_failed:"..media_id
- end
- local url = url_send_message .. "?access_token=" .. access_token
- local result, err = http.post(url, {
- ["Content-Type"] = "application/json"
- }, cjson.encode({
- touser = userid,
- msgtype = "video",
- agentid = agentid,
- video = {
- media_id = media_id,
- title = title
- }
- }))
- if not result then
- return false, err
- end
- local resp = cjson.decode(err)
- if resp.errcode == 0 then
- return true
- end
- return false, resp.errmsg
- end
- -- 发送卡片消息
- M.send_card_message = function(access_token,userid,agentid,message)
- local url = url_send_message .. "?access_token=" .. access_token
- local result,err = http.post(url,{
- ["Content-Type"] = "application/json"
- },cjson.encode({
- touser = userid,
- msgtype = "news",
- agentid = agentid,
- news = {
- articles = {
- message
- }
- }
- }))
- if not result then
- return false,err
- end
- local data = cjson.decode(err)
- if data.errcode == 0 then
- return true
- end
- return false,data.errmsg
- end
- -- 发送卡片消息
- M.send_template_card_message = function(access_token,userid,agentid,message)
- local url = url_send_message .. "?access_token=" .. access_token
- local result,err = http.post(url,{
- ["Content-Type"] = "application/json"
- },cjson.encode({
- touser = userid,
- msgtype = "template_card",
- agentid = agentid,
- template_card = message
- }))
- if not result then
- return false,err
- end
- local data = cjson.decode(err)
- if data.errcode == 0 then
- return true
- end
- return false,data.errmsg
- end
- -- 发送MMD消息
- M.send_markdown_message = function(access_token,userid,agentid,message)
- local url = url_send_message .. "?access_token=" .. access_token
- local result,err = http.post(url,{
- ["Content-Type"] = "application/json"
- },cjson.encode({
- touser = userid,
- msgtype = "markdown",
- agentid = agentid,
- markdown = {
- content = message
- }
- }))
- if not result then
- return false,err
- end
- local data = cjson.decode(err)
- if data.errcode == 0 then
- return true
- end
- return false,data.errmsg
- end
- return M
|