shixian-weixin_authorize 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +18 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +11 -0
  6. data/Gemfile +17 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +67 -0
  9. data/Rakefile +1 -0
  10. data/lib/weixin_authorize/api/custom.rb +124 -0
  11. data/lib/weixin_authorize/api/data_cube.rb +8 -0
  12. data/lib/weixin_authorize/api/groups.rb +49 -0
  13. data/lib/weixin_authorize/api/mass.rb +78 -0
  14. data/lib/weixin_authorize/api/media.rb +136 -0
  15. data/lib/weixin_authorize/api/menu.rb +36 -0
  16. data/lib/weixin_authorize/api/oauth.rb +38 -0
  17. data/lib/weixin_authorize/api/qrcode.rb +57 -0
  18. data/lib/weixin_authorize/api/template.rb +34 -0
  19. data/lib/weixin_authorize/api/user.rb +47 -0
  20. data/lib/weixin_authorize/api.rb +3 -0
  21. data/lib/weixin_authorize/carrierwave/weixin_uploader.rb +4 -0
  22. data/lib/weixin_authorize/client.rb +86 -0
  23. data/lib/weixin_authorize/config.rb +29 -0
  24. data/lib/weixin_authorize/handler/exceptions.rb +7 -0
  25. data/lib/weixin_authorize/handler/global_code.rb +89 -0
  26. data/lib/weixin_authorize/handler/result_handler.rb +52 -0
  27. data/lib/weixin_authorize/handler.rb +3 -0
  28. data/lib/weixin_authorize/js_ticket/object_store.rb +21 -0
  29. data/lib/weixin_authorize/js_ticket/redis_store.rb +41 -0
  30. data/lib/weixin_authorize/js_ticket/store.rb +40 -0
  31. data/lib/weixin_authorize/token/object_store.rb +25 -0
  32. data/lib/weixin_authorize/token/redis_store.rb +35 -0
  33. data/lib/weixin_authorize/token/store.rb +72 -0
  34. data/lib/weixin_authorize/version.rb +3 -0
  35. data/lib/weixin_authorize.rb +81 -0
  36. data/spec/1_fetch_access_token_spec.rb +43 -0
  37. data/spec/2_fetch_jsticket_spec.rb +10 -0
  38. data/spec/api/custom_spec.rb +58 -0
  39. data/spec/api/groups_spec.rb +54 -0
  40. data/spec/api/mass_spec.rb +70 -0
  41. data/spec/api/media_spec.rb +70 -0
  42. data/spec/api/medias/favicon.ico +0 -0
  43. data/spec/api/medias/ruby-logo.jpg +0 -0
  44. data/spec/api/menu_spec.rb +26 -0
  45. data/spec/api/qrcode_spec.rb +22 -0
  46. data/spec/api/template_spec.rb +40 -0
  47. data/spec/api/user_spec.rb +26 -0
  48. data/spec/spec_helper.rb +130 -0
  49. data/weixin_authorize.gemspec +34 -0
  50. metadata +202 -0
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+ module Api
4
+ module Qrcode
5
+ # http://mp.weixin.qq.com/wiki/index.php?title=生成带参数的二维码
6
+
7
+ # 临时二维码
8
+ def create_qr_scene(scene_id, expire_seconds=1800)
9
+ post_url = "#{qrcode_base_url}/create"
10
+ qrcode_infos = {action_name: "QR_SCENE", expire_seconds: expire_seconds}
11
+ qrcode_infos = qrcode_infos.merge(action_info(scene_id))
12
+ http_post(post_url, qrcode_infos)
13
+ end
14
+
15
+ # 永久二维码
16
+ # options: scene_id, scene_str
17
+ def create_qr_limit_scene(options)
18
+ scene_id = options[:scene_id]
19
+ scene_str = options[:scene_str]
20
+ post_url = "#{qrcode_base_url}/create"
21
+ qrcode_infos = {action_name: "QR_LIMIT_SCENE"}
22
+ qrcode_infos = qrcode_infos.merge(action_info(scene_id))
23
+ http_post(post_url, qrcode_infos)
24
+ end
25
+
26
+ # 为永久的字符串参数值
27
+ # options: scene_str
28
+ def create_qr_limit_str_scene(options)
29
+ scene_str = options[:scene_str]
30
+ post_url = "#{qrcode_base_url}/create"
31
+ qrcode_infos = {action_name: "QR_LIMIT_STR_SCENE"}
32
+ qrcode_infos = qrcode_infos.merge(action_info(nil, scene_str))
33
+ http_post(post_url, qrcode_infos)
34
+ end
35
+
36
+
37
+ # 通过ticket换取二维码, 直接访问即可显示!
38
+ def qr_code_url(ticket)
39
+ WeixinAuthorize.mp_endpoint("/showqrcode?ticket=#{ticket}")
40
+ end
41
+
42
+ private
43
+
44
+ def qrcode_base_url
45
+ "/qrcode"
46
+ end
47
+
48
+ def action_info(scene_id, scene_str=nil)
49
+ scene_info = {}
50
+ scene_info[:scene_id] = scene_id if !scene_id.nil?
51
+ scene_info[:scene_str] = scene_str if !scene_str.nil?
52
+ {action_info: {scene: scene_info}}
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+ module Api
4
+ module Template
5
+
6
+ # 设置所属行业
7
+ # 需要选择公众账号服务所处的2个行业,每月可更改1次所选行业;
8
+ # 初始化行业时,传入两个,每月更改时,传入一个即可。
9
+ def set_template_industry(industry_id1, industry_id2="")
10
+ industries = {industry_id1: industry_id1}
11
+ if industry_id2 != ""
12
+ industries.merge!({industry_id2: industry_id2})
13
+ end
14
+ http_post("/template/api_set_industry", industries)
15
+ end
16
+
17
+ # 获得模板ID
18
+ # code: 模板库中模板的编号,有“TM**”和“OPENTMTM**”等形式
19
+ def add_template(code)
20
+ http_post("/template/api_add_template", template_id_short: code)
21
+ end
22
+
23
+ # 发送模板消息
24
+ def send_template_msg(touser, template_id, url, topcolor, data)
25
+ msg = {
26
+ touser: touser, template_id: template_id,
27
+ url: url, topcolor: topcolor, data: data
28
+ }
29
+ http_post("/message/template/send", msg)
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+ module Api
4
+ module User
5
+
6
+ # 获取用户基本信息
7
+ # https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
8
+ # lang: zh_CN, zh_TW, en
9
+ def user(openid, lang="zh_CN")
10
+ user_info_url = "#{user_base_url}/info"
11
+ http_get(user_info_url, {openid: openid, lang: lang})
12
+ end
13
+
14
+ # 获取关注者列表
15
+ # https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID
16
+ def followers(next_openid="")
17
+ followers_url = "#{user_base_url}/get"
18
+ http_get(followers_url, {next_openid: next_openid})
19
+ end
20
+
21
+ # 设置备注名
22
+ # http请求方式: POST(请使用https协议)
23
+ # https://api.weixin.qq.com/cgi-bin/user/info/updateremark?access_token=ACCESS_TOKEN
24
+ # POST数据格式:JSON
25
+ # POST数据例子:
26
+ # {
27
+ # "openid":"oDF3iY9ffA-hqb2vVvbr7qxf6A0Q",
28
+ # "remark":"pangzi"
29
+ # }
30
+ def update_remark(openid, remark)
31
+ update_url = "/user/info/updateremark"
32
+ payload = {
33
+ openid: openid,
34
+ remark: remark
35
+ }
36
+ http_post(update_url, payload)
37
+ end
38
+
39
+ private
40
+
41
+ def user_base_url
42
+ "/user"
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,3 @@
1
+ Dir["#{File.dirname(__FILE__)}/api/*.rb"].each do |path|
2
+ require path
3
+ end
@@ -0,0 +1,4 @@
1
+ module WeixinAuthorize
2
+ class WeixinUploader < CarrierWave::Uploader::Base
3
+ end
4
+ end
@@ -0,0 +1,86 @@
1
+ # encoding: utf-8
2
+ require "redis"
3
+ require 'digest/md5'
4
+ module WeixinAuthorize
5
+
6
+ class Client
7
+ include Api::User
8
+ include Api::Menu
9
+ include Api::Custom
10
+ include Api::Groups
11
+ include Api::Qrcode
12
+ include Api::Media
13
+ include Api::Mass
14
+ include Api::Oauth
15
+ include Api::Template
16
+
17
+ attr_accessor :app_id, :app_secret, :expired_at # Time.now + expires_in
18
+ attr_accessor :access_token, :redis_key
19
+ attr_accessor :jsticket, :jsticket_expired_at, :jsticket_redis_key
20
+
21
+ def initialize(app_id, app_secret, redis_key=nil)
22
+ @app_id = app_id
23
+ @app_secret = app_secret
24
+ @jsticket_expired_at = @expired_at = Time.now.to_i
25
+ @redis_key = security_redis_key(redis_key || "weixin_#{app_id}")
26
+ @jsticket_redis_key = security_redis_key("js_sdk_#{app_id}")
27
+ end
28
+
29
+ # return token
30
+ def get_access_token
31
+ token_store.access_token
32
+ end
33
+
34
+ # 检查appid和app_secret是否有效。
35
+ def is_valid?
36
+ token_store.valid?
37
+ end
38
+
39
+ def token_store
40
+ Token::Store.init_with(self)
41
+ end
42
+
43
+ def jsticket_store
44
+ JsTicket::Store.init_with(self)
45
+ end
46
+
47
+ def get_jsticket
48
+ jsticket_store.jsticket
49
+ end
50
+
51
+ # 获取js sdk 签名包
52
+ def get_jssign_package(url)
53
+ timestamp = Time.now.to_i
54
+ noncestr = SecureRandom.hex(16)
55
+ str = "jsapi_ticket=#{get_jsticket}&noncestr=#{noncestr}&timestamp=#{timestamp}&url=#{url}";
56
+ signature = Digest::SHA1.hexdigest(str)
57
+ {
58
+ "appId" => app_id, "nonceStr" => noncestr,
59
+ "timestamp" => timestamp, "url" => url,
60
+ "signature" => signature, "rawString" => str
61
+ }
62
+ end
63
+
64
+ # 暴露出:http_get,http_post两个方法,方便第三方开发者扩展未开发的微信API。
65
+ def http_get(url, headers={}, endpoint="plain")
66
+ headers = headers.merge(access_token_param)
67
+ WeixinAuthorize.http_get_without_token(url, headers, endpoint)
68
+ end
69
+
70
+ def http_post(url, payload={}, headers={}, endpoint="plain")
71
+ headers = access_token_param.merge(headers)
72
+ WeixinAuthorize.http_post_without_token(url, payload, headers, endpoint)
73
+ end
74
+
75
+ private
76
+
77
+ def access_token_param
78
+ {access_token: get_access_token}
79
+ end
80
+
81
+ def security_redis_key(key)
82
+ Digest::MD5.hexdigest(key.to_s).upcase
83
+ end
84
+
85
+ end
86
+ end
@@ -0,0 +1,29 @@
1
+ module WeixinAuthorize
2
+
3
+ class << self
4
+
5
+ attr_accessor :config
6
+
7
+ def configure
8
+ yield self.config ||= Config.new
9
+ end
10
+
11
+ def weixin_redis
12
+ return nil if config.nil?
13
+ @redis ||= config.redis
14
+ end
15
+
16
+ # 可选配置: RestClient timeout, etc.
17
+ # key 必须是符号
18
+ def rest_client_options
19
+ if config.nil?
20
+ return {timeout: 5, open_timeout: 5, verify_ssl: true}
21
+ end
22
+ config.rest_client_options
23
+ end
24
+ end
25
+
26
+ class Config
27
+ attr_accessor :redis, :rest_client_options
28
+ end
29
+ end
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+
4
+ class ValidAccessTokenException < RuntimeError
5
+ end
6
+
7
+ end
@@ -0,0 +1,89 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+
4
+ GLOBAL_CODES = {
5
+ -1 => "系统繁忙",
6
+ 0 => "请求成功",
7
+ 40001 => "获取access_token时AppSecret错误,或者access_token无效",
8
+ 40002 => "不合法的凭证类型",
9
+ 40003 => "不合法的OpenID",
10
+ 40004 => "不合法的媒体文件类型",
11
+ 40005 => "不合法的文件类型",
12
+ 40006 => "不合法的文件大小",
13
+ 40007 => "不合法的媒体文件id",
14
+ 40008 => "不合法的消息类型",
15
+ 40009 => "不合法的图片文件大小",
16
+ 40010 => "不合法的语音文件大小",
17
+ 40011 => "不合法的视频文件大小",
18
+ 40012 => "不合法的缩略图文件大小",
19
+ 40013 => "不合法的APPID",
20
+ 40014 => "不合法的access_token",
21
+ 40015 => "不合法的菜单类型",
22
+ 40016 => "不合法的按钮个数",
23
+ 40017 => "不合法的按钮个数",
24
+ 40018 => "不合法的按钮名字长度",
25
+ 40019 => "不合法的按钮KEY长度",
26
+ 40020 => "不合法的按钮URL长度",
27
+ 40021 => "不合法的菜单版本号",
28
+ 40022 => "不合法的子菜单级数",
29
+ 40023 => "不合法的子菜单按钮个数",
30
+ 40024 => "不合法的子菜单按钮类型",
31
+ 40025 => "不合法的子菜单按钮名字长度",
32
+ 40026 => "不合法的子菜单按钮KEY长度",
33
+ 40027 => "不合法的子菜单按钮URL长度",
34
+ 40028 => "不合法的自定义菜单使用用户",
35
+ 40029 => "不合法的oauth_code",
36
+ 40030 => "不合法的refresh_token",
37
+ 40031 => "不合法的openid列表",
38
+ 40032 => "不合法的openid列表长度",
39
+ 40033 => "不合法的请求字符,不能包含xxxx格式的字符",
40
+ 40035 => "不合法的参数",
41
+ 40038 => "不合法的请求格式",
42
+ 40039 => "不合法的URL长度",
43
+ 40050 => "不合法的分组id",
44
+ 40051 => "分组名字不合法",
45
+ 41001 => "缺少access_token参数",
46
+ 41002 => "缺少appid参数",
47
+ 41003 => "缺少refresh_token参数",
48
+ 41004 => "缺少secret参数",
49
+ 41005 => "缺少多媒体文件数据",
50
+ 41006 => "缺少media_id参数",
51
+ 41007 => "缺少子菜单数据",
52
+ 41008 => "缺少oauth code",
53
+ 41009 => "缺少openid",
54
+ 42001 => "access_token超时",
55
+ 42002 => "refresh_token超时",
56
+ 42003 => "oauth_code超时",
57
+ 43001 => "需要GET请求",
58
+ 43002 => "需要POST请求",
59
+ 43003 => "需要HTTPS请求",
60
+ 43004 => "需要接收者关注",
61
+ 43005 => "需要好友关系",
62
+ 44001 => "多媒体文件为空",
63
+ 44002 => "POST的数据包为空",
64
+ 44003 => "图文消息内容为空",
65
+ 44004 => "文本消息内容为空",
66
+ 45001 => "多媒体文件大小超过限制",
67
+ 45002 => "消息内容超过限制",
68
+ 45003 => "标题字段超过限制",
69
+ 45004 => "描述字段超过限制",
70
+ 45005 => "链接字段超过限制",
71
+ 45006 => "图片链接字段超过限制",
72
+ 45007 => "语音播放时间超过限制",
73
+ 45008 => "图文消息超过限制",
74
+ 45009 => "接口调用超过限制",
75
+ 45010 => "创建菜单个数超过限制",
76
+ 45015 => "回复时间超过限制",
77
+ 45016 => "系统分组,不允许修改",
78
+ 45017 => "分组名字过长",
79
+ 45018 => "分组数量超过上限",
80
+ 46001 => "不存在媒体数据",
81
+ 46002 => "不存在的菜单版本",
82
+ 46003 => "不存在的菜单数据",
83
+ 46004 => "不存在的用户",
84
+ 47001 => "解析JSON/XML内容错误",
85
+ 48001 => "api功能未授权",
86
+ 50001 => "用户未授权该api"
87
+ }unless defined?(GLOBAL_CODES)
88
+
89
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+
4
+ class ResultHandler
5
+
6
+ attr_accessor :code, :cn_msg, :en_msg, :result
7
+
8
+ def initialize(code, en_msg, result={})
9
+ @code = code || OK_CODE
10
+ @en_msg = en_msg || OK_MSG
11
+ @cn_msg = GLOBAL_CODES[@code.to_i]
12
+ @result = package_result(result)
13
+ end
14
+
15
+ # This method is to valid the current request if is true or is false
16
+ def is_ok?
17
+ code == OK_CODE
18
+ end
19
+ alias_method :ok?, :is_ok?
20
+
21
+ # e.g.:
22
+ # 45009: api freq out of limit(接口调用超过限制)
23
+ def full_message
24
+ "#{code}: #{en_msg}(#{cn_msg})."
25
+ end
26
+ alias_method :full_messages, :full_message
27
+
28
+ def full_error_message
29
+ full_message if !is_ok?
30
+ end
31
+ alias_method :full_error_messages, :full_error_message
32
+ alias_method :errors, :full_error_message
33
+
34
+ private
35
+
36
+ # if define Rails constant
37
+ # result = WeixinAuthorize::ResultHandler.new("0", "success", {:ok => "true"})
38
+ # result.result["ok"] #=> true
39
+ # result.result[:ok] #=> true
40
+ # result.result['ok'] #=> true
41
+ def package_result(result)
42
+ return result if !result.is_a?(Hash)
43
+ if defined?(Rails)
44
+ ActiveSupport::HashWithIndifferentAccess.new(result)
45
+ else
46
+ result
47
+ end
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,3 @@
1
+ require "weixin_authorize/handler/global_code"
2
+ require "weixin_authorize/handler/result_handler"
3
+ require "weixin_authorize/handler/exceptions"
@@ -0,0 +1,21 @@
1
+ module WeixinAuthorize
2
+ module JsTicket
3
+ class ObjectStore < Store
4
+
5
+ def jsticket_expired?
6
+ # 如果当前token过期时间小于现在的时间,则重新获取一次
7
+ client.jsticket_expired_at <= Time.now.to_i
8
+ end
9
+
10
+ def jsticket
11
+ super
12
+ client.jsticket
13
+ end
14
+
15
+ def refresh_jsticket
16
+ super
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,41 @@
1
+ module WeixinAuthorize
2
+ module JsTicket
3
+ class RedisStore < Store
4
+ JSTICKET = "jsticket"
5
+ EXPIRED_AT = "expired_at"
6
+
7
+ def jsticket_expired?
8
+ weixin_redis.hvals(client.jsticket_redis_key).empty?
9
+ end
10
+
11
+ def refresh_jsticket
12
+ super
13
+ weixin_redis.hmset(
14
+ client.jsticket_redis_key,
15
+ JSTICKET,
16
+ client.jsticket,
17
+ EXPIRED_AT,
18
+ client.jsticket_expired_at
19
+ )
20
+ weixin_redis.expireat(
21
+ client.jsticket_redis_key,
22
+ client.jsticket_expired_at.to_i
23
+ )
24
+ end
25
+
26
+ def jsticket
27
+ super
28
+ client.jsticket = weixin_redis.hget(client.jsticket_redis_key, JSTICKET)
29
+ client.jsticket_expired_at = weixin_redis.hget(
30
+ client.jsticket_redis_key,
31
+ EXPIRED_AT
32
+ )
33
+ client.jsticket
34
+ end
35
+
36
+ def weixin_redis
37
+ WeixinAuthorize.weixin_redis
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+ module JsTicket
4
+ class Store
5
+
6
+ attr_accessor :client
7
+
8
+ def initialize(client)
9
+ @client = client
10
+ end
11
+
12
+ def self.init_with(client)
13
+ if WeixinAuthorize.weixin_redis.nil?
14
+ ObjectStore.new(client)
15
+ else
16
+ RedisStore.new(client)
17
+ end
18
+ end
19
+
20
+ def jsticket_expired?
21
+ raise NotImplementedError, "Subclasses must implement a jsticket_expired? method"
22
+ end
23
+
24
+ def refresh_jsticket
25
+ set_jsticket
26
+ end
27
+
28
+ def jsticket
29
+ refresh_jsticket if jsticket_expired?
30
+ end
31
+
32
+ def set_jsticket
33
+ result = client.http_get("/ticket/getticket", {type: 1}).result
34
+ client.jsticket = result["ticket"]
35
+ client.jsticket_expired_at = result["expires_in"] + Time.now.to_i
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+ module Token
4
+ class ObjectStore < Store
5
+
6
+ def valid?
7
+ super
8
+ end
9
+
10
+ def token_expired?
11
+ # 如果当前token过期时间小于现在的时间,则重新获取一次
12
+ client.expired_at <= Time.now.to_i
13
+ end
14
+
15
+ def refresh_token
16
+ super
17
+ end
18
+
19
+ def access_token
20
+ super
21
+ client.access_token
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+ module Token
4
+ class RedisStore < Store
5
+
6
+ def valid?
7
+ weixin_redis.del(client.redis_key)
8
+ super
9
+ end
10
+
11
+ def token_expired?
12
+ weixin_redis.hvals(client.redis_key).empty?
13
+ end
14
+
15
+ def refresh_token
16
+ super
17
+ weixin_redis.hmset(client.redis_key, "access_token", client.access_token,
18
+ "expired_at", client.expired_at)
19
+ weixin_redis.expireat(client.redis_key, client.expired_at.to_i-10) # 提前10秒超时
20
+ end
21
+
22
+ def access_token
23
+ super
24
+ client.access_token = weixin_redis.hget(client.redis_key, "access_token")
25
+ client.expired_at = weixin_redis.hget(client.redis_key, "expired_at")
26
+ client.access_token
27
+ end
28
+
29
+ def weixin_redis
30
+ WeixinAuthorize.weixin_redis
31
+ end
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1,72 @@
1
+ # encoding: utf-8
2
+ module WeixinAuthorize
3
+ module Token
4
+ class Store
5
+
6
+ attr_accessor :client
7
+
8
+ def initialize(client)
9
+ @client = client
10
+ end
11
+
12
+ def self.init_with(client)
13
+ if WeixinAuthorize.weixin_redis.nil?
14
+ ObjectStore.new(client)
15
+ else
16
+ RedisStore.new(client)
17
+ end
18
+ end
19
+
20
+ def valid?
21
+ authenticate["valid"]
22
+ end
23
+
24
+ def authenticate
25
+ auth_result = http_get_access_token
26
+ auth = false
27
+ if auth_result.is_ok?
28
+ set_access_token(auth_result.result)
29
+ auth = true
30
+ end
31
+ {"valid" => auth, "handler" => auth_result}
32
+ end
33
+
34
+ def refresh_token
35
+ handle_valid_exception
36
+ set_access_token
37
+ end
38
+
39
+ def access_token
40
+ refresh_token if token_expired?
41
+ end
42
+
43
+ def token_expired?
44
+ raise NotImplementedError, "Subclasses must implement a token_expired? method"
45
+ end
46
+
47
+ def set_access_token(access_token_infos=nil)
48
+ token_infos = access_token_infos || http_get_access_token.result
49
+ client.access_token = token_infos["access_token"]
50
+ client.expired_at = Time.now.to_i + token_infos["expires_in"].to_i
51
+ end
52
+
53
+ def http_get_access_token
54
+ WeixinAuthorize.http_get_without_token("/token", authenticate_headers)
55
+ end
56
+
57
+ def authenticate_headers
58
+ {grant_type: GRANT_TYPE, appid: client.app_id, secret: client.app_secret}
59
+ end
60
+
61
+ private
62
+
63
+ def handle_valid_exception
64
+ auth_result = authenticate
65
+ if !auth_result["valid"]
66
+ result_handler = auth_result["handler"]
67
+ raise ValidAccessTokenException, result_handler.full_error_message
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,3 @@
1
+ module WeixinAuthorize
2
+ VERSION = "1.6.2"
3
+ end