219 lines
6.7 KiB
Lua
219 lines
6.7 KiB
Lua
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 .. "×tamp=" .. 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
|