Files
daydaytalk-fwutils/target/tencent/wxofficial.lua
2026-01-08 21:58:41 +08:00

219 lines
6.7 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
require("app.app")
local http = require("socket.http")
local ltn12 = require("ltn12")
local httpclient = require("fwutils.httpclient")
local cache = require("fwutils.cache")
local M = {}
-- access_token 的 url
M.url_get_access_token = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential"
-- 获取用户access_token的url
M.url_get_user_access_token = "https://api.weixin.qq.com/sns/oauth2/access_token?grant_type=authorization_code"
-- 获取用户信息的url
M.url_get_user_info = "https://api.weixin.qq.com/sns/userinfo?lang=zh_CN"
-- 授权地址
M.url_auth = "https://open.weixin.qq.com/connect/oauth2/authorize"
-- 模板消息
M.url_template_message = "https://api.weixin.qq.com/cgi-bin/message/template/send"
-- 获取 access_token
M.get_access_token = function(appid, appsecret)
-- local value = cache.get_json("wxofficial_info")
-- if value then
-- -- 是否距离过期至少还有5分钟
-- if value.expires_seconds > os.time() + 300 then
-- return true, value.access_token
-- end
-- end
-- 如果 appid 和 appsecret 为空,则返回 nil
if appid == nil or appid == "" then
return false, "appid 为空"
end
if appsecret == nil or appsecret == "" then
return false, "appsecret 为空"
end
-- 先检查有没有过期
local cache_data = cache.get_json(tostring("wxofficial_info_"..appid))
if cache_data then
if cache_data.update_time and cache_data.access_token then
-- 检查是否过期
if os.time() - cache_data.update_time < 7200 then
return true,cache_data.access_token
end
end
end
local result, data = httpclient.get(M.url_get_access_token .. "&appid=" .. appid .. "&secret=" .. appsecret)
if not result then
return false, data
end
local body = cjson.decode(data)
if body.errcode ~= nil and body.errcode ~= 0 then
return false, body.errmsg
end
-- 更新
cache.set_json(tostring("wxofficial_info_"..appid),{
update_time = os.time(),
access_token = body.access_token
})
return true,body.access_token
end
-- 获取用户access_token
M.get_user_access_token = function(appid, appsecret, code)
local result, data = httpclient.get(M.url_get_user_access_token .. "&appid=" .. appid .. "&secret=" .. appsecret .. "&code=" .. code)
if not result then
return false, data
end
local body = cjson.decode(data)
if body.errcode ~= nil and body.errcode ~= 0 then
return false, body.errmsg
end
return true, body
end
-- 获取用户信息
M.get_user_info = function(access_token, openid)
local url = M.url_get_user_info .. "&access_token=" .. access_token .. "&openid=" .. openid
local result, data = httpclient.get(url)
if not result then
return false, data
end
local body = cjson.decode(data)
if body.errcode ~= nil and body.errcode ~= 0 then
return false, body.errmsg
end
return true, body
end
-- 生成授权地址
M.generate_auth_url = function(appid, redirect_uri)
return M.url_auth .. "?appid=" .. appid .. "&redirect_uri=" .. redirect_uri .. "&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect"
end
-- 发送模板消息
M.send_template_message = function(appid, appsecret, openid, template_id, jump_url, data)
local ok, access_token = M.get_access_token(appid, appsecret)
if not ok then
return false, access_token
end
local url = M.url_template_message .. "?access_token=" .. access_token
local body = {
touser = openid,
template_id = template_id,
url = jump_url,
data = data,
appid = appid
}
local result, response = httpclient.post(url, {
["Content-Type"] = "application/json"
}, cjson.encode(body))
if not result then
return false, response
end
local res_json = cjson.decode(response)
if res_json.errcode ~= 0 then
return false, res_json.errmsg
end
return true
end
-- 生成一次性订阅确认地址
M.generate_subscribe_confirm_url = function(appid, scene, template_id, redirect_uri, reserved)
return "https://mp.weixin.qq.com/mp/subscribemsg?action=get_confirm&appid=" .. appid .. "&scene=" .. scene .. "&template_id=" .. template_id .. "&redirect_url=" .. redirect_uri .. "&#wechat_redirect"
end
--------------------------------------------------------------------------------
-- 以下为新增的部分用于微信JS SDK 配置
-- 生成随机字符串函数
local function generate_nonce_str(length)
--math.randomseed(os.time() + math.random()) -- 增加随机种子
local chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
local res = {}
for i = 1, (length or 16) do
local rand = math.random(1, #chars)
res[#res+1] = string.sub(chars, rand, rand)
end
return table.concat(res)
end
-- 获取 jsapi_ticket
M.get_jsapi_ticket = function(appid, appsecret)
local ticket_info = cache.get_json("wxjsapi_ticket")
if ticket_info then
if ticket_info.expires > os.time() + 300 then
return true, ticket_info.ticket
end
end
local ok, access_token = M.get_access_token(appid, appsecret)
if not ok then
return false, access_token
end
local ticket_url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" .. access_token .. "&type=jsapi"
local result, data = httpclient.get(ticket_url)
if not result then
return false, data
end
local body = cjson.decode(data)
if body.errcode ~= 0 then
return false, body.errmsg
end
cache.set_json("wxjsapi_ticket", {
ticket = body.ticket,
expires = os.time() + body.expires_in
})
return true, body.ticket
end
-- 获取微信JS SDK所需的配置参数
-- 参数 current_url 必须是当前网页的完整 URL不包含#号后的部分)
M.get_js_sdk_config = function(appid, appsecret, current_url)
local ok, jsapi_ticket = M.get_jsapi_ticket(appid, appsecret)
if not ok then
return false, jsapi_ticket..",err"
end
local nonceStr = generate_nonce_str(16)
local timestamp = os.time()
-- 拼接待签名字符串,注意顺序及格式严格按照微信要求
local str = "jsapi_ticket=" .. jsapi_ticket .. "&noncestr=" .. nonceStr .. "&timestamp=" .. timestamp .. "&url=" .. current_url
-- 计算 SHA1 签名(需在 OpenResty 下使用 ngx.sha1_bin 和 resty.string.to_hex
local signature = codec.sha1(str)
return true, {
appId = appid,
timestamp = timestamp,
nonceStr = nonceStr,
signature = signature
}
end
--------------------------------------------------------------------------------
return M