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