weixin_rails_middleware 1.2.1 → 1.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/weixin_rails_middleware/weixin_controller.rb +15 -8
- data/lib/generators/templates/install_weixin_rails_middleware.rb +1 -1
- data/lib/generators/templates/weixin_controller.rb +3 -2
- data/lib/weixin_rails_middleware.rb +1 -1
- data/lib/weixin_rails_middleware/adapter.rb +3 -0
- data/lib/weixin_rails_middleware/adapter/multiple_public_account.rb +30 -0
- data/lib/weixin_rails_middleware/adapter/single_public_account.rb +29 -0
- data/lib/weixin_rails_middleware/adapter/weixin_adapter.rb +74 -0
- data/lib/weixin_rails_middleware/configuration.rb +2 -3
- data/lib/weixin_rails_middleware/engine.rb +0 -1
- data/lib/weixin_rails_middleware/helpers/auto_generate_weixin_token_secret_key.rb +3 -4
- data/lib/weixin_rails_middleware/helpers/unique_token_helper.rb +2 -5
- data/lib/weixin_rails_middleware/models/message.rb +1 -1
- data/lib/weixin_rails_middleware/models/reply_message.rb +1 -2
- data/lib/weixin_rails_middleware/version.rb +1 -1
- metadata +6 -3
- data/lib/weixin_rails_middleware/helpers/weixin_authorize_helper.rb +0 -74
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 636d0f84432996fd76df3c15716065b775a77379
|
4
|
+
data.tar.gz: 6228287ca1e489b6370f95e1a5aa7b5161def9d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5f5e0d4d176122697db34adf00a75e228d820eddea54ca11adc881e7bf5c18f284d9ee8e77c628309776c17dc2db67256f61faf9c449075b22c1eb63ba3e8ce0
|
7
|
+
data.tar.gz: 8b462a16a5e24a00ba0d0dd3ee7f890d367bd216b85b847b57ab5697cfbd7d185e9fbe7868a61d52457cda788252b4cf275739108c2c013785aa17edfb09aa53
|
@@ -1,15 +1,12 @@
|
|
1
1
|
module WeixinRailsMiddleware
|
2
2
|
class WeixinController < ActionController::Base
|
3
3
|
include ReplyWeixinMessageHelper
|
4
|
-
include ConfigurationHelpers
|
5
|
-
include WeixinAuthorizeHelper
|
6
4
|
|
7
5
|
skip_before_filter :verify_authenticity_token
|
8
|
-
before_filter :
|
6
|
+
before_filter :initialize_adapter, :check_weixin_legality, only: [:index, :reply]
|
9
7
|
before_filter :set_weixin_public_account, :set_weixin_message, only: :reply
|
10
8
|
|
11
9
|
def index
|
12
|
-
render text: params[:echostr]
|
13
10
|
end
|
14
11
|
|
15
12
|
def reply
|
@@ -17,16 +14,26 @@ module WeixinRailsMiddleware
|
|
17
14
|
|
18
15
|
protected
|
19
16
|
|
17
|
+
def initialize_adapter
|
18
|
+
@weixin_adapter ||= Adapter::WexinAdapter.init_with(params)
|
19
|
+
end
|
20
|
+
|
21
|
+
def check_weixin_legality
|
22
|
+
check_result = @weixin_adapter.check_weixin_legality
|
23
|
+
valid = check_result.delete(:valid)
|
24
|
+
render check_result if action_name == "index"
|
25
|
+
return valid
|
26
|
+
end
|
27
|
+
|
20
28
|
## Callback
|
21
29
|
# e.g. will generate +@weixin_public_account+
|
22
30
|
def set_weixin_public_account
|
23
|
-
|
24
|
-
@weixin_public_account ||= current_weixin_public_account
|
31
|
+
@weixin_public_account ||= @weixin_adapter.current_weixin_public_account
|
25
32
|
end
|
26
33
|
|
27
34
|
def set_weixin_message
|
28
|
-
# Get the
|
29
|
-
@weixin_message ||=
|
35
|
+
# Get the current weixin message
|
36
|
+
@weixin_message ||= Message.factory(request.body.read)
|
30
37
|
end
|
31
38
|
|
32
39
|
end
|
@@ -7,7 +7,7 @@ WeixinRailsMiddleware.configure do |config|
|
|
7
7
|
## Config public_account_class if you SAVE public_account into database ##
|
8
8
|
# Th first configure is fit for your weixin public_account is saved in database.
|
9
9
|
# +public_account_class+ The class name that to save your public_account
|
10
|
-
# config.public_account_class = ""
|
10
|
+
# config.public_account_class = "PublicAccount"
|
11
11
|
|
12
12
|
## Here configure is for you DON'T WANT TO SAVE your public account into database ##
|
13
13
|
# Or the other configure is fit for only one weixin public_account
|
@@ -52,7 +52,7 @@ WeixinRailsMiddleware::WeixinController.class_eval do
|
|
52
52
|
when "subscribe" # 关注公众账号
|
53
53
|
if @keyword.present?
|
54
54
|
# 扫描带参数二维码事件: 1. 用户未关注时,进行关注后的事件推送
|
55
|
-
reply_text_message("扫描带参数二维码事件: 1. 用户未关注时,进行关注后的事件推送, keyword: #{@keyword}")
|
55
|
+
return reply_text_message("扫描带参数二维码事件: 1. 用户未关注时,进行关注后的事件推送, keyword: #{@keyword}")
|
56
56
|
end
|
57
57
|
reply_text_message("关注公众账号")
|
58
58
|
when "unsubscribe" # 取消关注
|
@@ -78,7 +78,7 @@ WeixinRailsMiddleware::WeixinController.class_eval do
|
|
78
78
|
# <Format><![CDATA[Format]]></Format>
|
79
79
|
def response_voice_message(options={})
|
80
80
|
@media_id = @weixin_message.MediaId # 可以调用多媒体文件下载接口拉取数据。
|
81
|
-
@format = @weixin_message.
|
81
|
+
@format = @weixin_message.Format
|
82
82
|
reply_text_message("回复语音信息: #{@keyword}")
|
83
83
|
end
|
84
84
|
|
@@ -91,6 +91,7 @@ WeixinRailsMiddleware::WeixinController.class_eval do
|
|
91
91
|
reply_text_message("回复视频信息")
|
92
92
|
end
|
93
93
|
|
94
|
+
# @weixin_message 在rails 3时如果调用不存在的方法,会出现错误。rails 4好像没有问题。
|
94
95
|
def set_keyword
|
95
96
|
@keyword = @weixin_message.Content || # 文本消息
|
96
97
|
@weixin_message.EventKey || # 事件推送
|
@@ -4,7 +4,7 @@ require "weixin_rails_middleware/models/message"
|
|
4
4
|
require "weixin_rails_middleware/models/reply_message"
|
5
5
|
require "weixin_rails_middleware/helpers/reply_weixin_message_helper"
|
6
6
|
require "weixin_rails_middleware/helpers/unique_token_helper"
|
7
|
-
require "weixin_rails_middleware/
|
7
|
+
require "weixin_rails_middleware/adapter"
|
8
8
|
require "weixin_rails_middleware/helpers/auto_generate_weixin_token_secret_key"
|
9
9
|
|
10
10
|
module WeixinRailsMiddleware
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module WeixinRailsMiddleware
|
3
|
+
module Adapter
|
4
|
+
class MultiplePublicAccount < WexinAdapter
|
5
|
+
|
6
|
+
def check_weixin_legality
|
7
|
+
return render_authorize_result(404) if !is_weixin_secret_key_valid?
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
# check the token from Weixin Service is exist in local store.
|
12
|
+
def is_weixin_secret_key_valid?
|
13
|
+
current_weixin_public_account.present?
|
14
|
+
end
|
15
|
+
|
16
|
+
def current_weixin_token
|
17
|
+
current_weixin_public_account.try(DEFAULT_TOKEN_COLUMN_NAME)
|
18
|
+
end
|
19
|
+
|
20
|
+
def current_weixin_public_account
|
21
|
+
self.class.token_model_class.where("#{DEFAULT_WEIXIN_SECRET_KEY}" => weixin_secret_key).first
|
22
|
+
end
|
23
|
+
|
24
|
+
def error_msg
|
25
|
+
"#{__FILE__}:#{__LINE__}: RecordNotFound - Couldn't find #{self.class.token_model} with weixin_secret_key=#{weixin_secret_key}"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module WeixinRailsMiddleware
|
3
|
+
module Adapter
|
4
|
+
class SinglePublicAccount < WexinAdapter
|
5
|
+
|
6
|
+
def check_weixin_legality
|
7
|
+
return render_authorize_result if !is_weixin_secret_key_valid?
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def is_weixin_secret_key_valid?
|
12
|
+
weixin_secret_key == self.class.weixin_secret_string
|
13
|
+
end
|
14
|
+
|
15
|
+
def current_weixin_token
|
16
|
+
self.class.weixin_token_string
|
17
|
+
end
|
18
|
+
|
19
|
+
def current_weixin_public_account
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def error_msg
|
24
|
+
"#{__FILE__}:#{__LINE__}: Weixin secret string NotMatch."
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module WeixinRailsMiddleware
|
3
|
+
module Adapter
|
4
|
+
class WexinAdapter
|
5
|
+
extend ConfigurationHelpers
|
6
|
+
|
7
|
+
attr_accessor :signature, :timestamp, :nonce, :echostr
|
8
|
+
attr_accessor :weixin_secret_key
|
9
|
+
|
10
|
+
def initialize(weixin_params)
|
11
|
+
@weixin_secret_key = weixin_params[:weixin_secret_key]
|
12
|
+
# 以下参数为什么加空字符串默认值的原因:
|
13
|
+
# SB微信偶尔会再重新发一次get请求,但是不会带上signature,timestamp,nonce的参数
|
14
|
+
# 一个预防措施吧。
|
15
|
+
@signature = weixin_params[:signature] || ''
|
16
|
+
@timestamp = weixin_params[:timestamp] || ''
|
17
|
+
@nonce = weixin_params[:nonce] || ''
|
18
|
+
@echostr = weixin_params[:echostr] || ''
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.init_with(weixin_params)
|
22
|
+
if weixin_token_string.present?
|
23
|
+
SinglePublicAccount.new(weixin_params)
|
24
|
+
else
|
25
|
+
MultiplePublicAccount.new(weixin_params)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def check_weixin_legality
|
30
|
+
return render_authorize_result(403, self.class.error_msg) if !is_signature_valid?
|
31
|
+
render_authorize_result(200, echostr, true)
|
32
|
+
end
|
33
|
+
|
34
|
+
def is_signature_valid?
|
35
|
+
sort_params = [current_weixin_token, timestamp, nonce].sort.join
|
36
|
+
current_signature = Digest::SHA1.hexdigest(sort_params)
|
37
|
+
return true if current_signature == signature
|
38
|
+
false
|
39
|
+
end
|
40
|
+
|
41
|
+
def current_weixin_public_account
|
42
|
+
raise NotImplementedError, "Subclasses must implement current_weixin_public_account method"
|
43
|
+
end
|
44
|
+
|
45
|
+
def current_weixin_token
|
46
|
+
raise NotImplementedError, "Subclasses must implement current_weixin_token method"
|
47
|
+
end
|
48
|
+
|
49
|
+
def is_weixin_secret_key_valid?
|
50
|
+
raise NotImplementedError, "Subclasses must implement is_weixin_secret_key_valid? method"
|
51
|
+
end
|
52
|
+
|
53
|
+
class << self
|
54
|
+
def error_msg
|
55
|
+
"#{__FILE__}:#{__LINE__}: Weixin signature NotMatch"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# render weixin server authorize results
|
62
|
+
def render_authorize_result(status=403, text=nil, valid=false)
|
63
|
+
text = text || error_msg
|
64
|
+
Rails.logger.error(text) if status != 200
|
65
|
+
{text: text, status: status, valid: valid}
|
66
|
+
end
|
67
|
+
|
68
|
+
def error_msg
|
69
|
+
self.class.error_msg
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -15,9 +15,8 @@ module WeixinRailsMiddleware
|
|
15
15
|
end
|
16
16
|
|
17
17
|
class Configuration
|
18
|
-
attr_accessor :public_account_class
|
19
|
-
attr_accessor :weixin_secret_string
|
20
|
-
|
18
|
+
attr_accessor :public_account_class
|
19
|
+
attr_accessor :weixin_secret_string, :weixin_token_string
|
21
20
|
end
|
22
21
|
|
23
22
|
module ConfigurationHelpers
|
@@ -5,7 +5,6 @@ module WeixinRailsMiddleware
|
|
5
5
|
included do
|
6
6
|
|
7
7
|
before_create do
|
8
|
-
# TODO: refactor
|
9
8
|
self.weixin_secret_key = generate_weixin_secret_key
|
10
9
|
self.weixin_token = WeiXinUniqueToken.generate
|
11
10
|
end
|
@@ -13,8 +12,8 @@ module WeixinRailsMiddleware
|
|
13
12
|
|
14
13
|
private
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
def generate_weixin_secret_key
|
16
|
+
WeiXinUniqueToken.generate(generator: :urlsafe_base64, size: 32).downcase
|
17
|
+
end
|
19
18
|
end
|
20
19
|
end
|
@@ -5,11 +5,8 @@ module WeixinRailsMiddleware
|
|
5
5
|
generator_method_type = options.delete(:generator).try(:to_sym) || :hex
|
6
6
|
generator_method = SecureRandom.method(generator_method_type)
|
7
7
|
token_size = options.delete(:size).try(:to_i) || 12
|
8
|
-
if generator_method_type
|
9
|
-
|
10
|
-
else
|
11
|
-
generator_method.call()
|
12
|
-
end
|
8
|
+
return generator_method.call if generator_method_type == :uuid
|
9
|
+
generator_method.call(token_size)
|
13
10
|
end
|
14
11
|
end
|
15
12
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# encoding: utf-8
|
2
2
|
# ref: https://github.com/wolfg1969/rack-weixin/lib/weixin/model.rb
|
3
3
|
require 'roxml'
|
4
4
|
|
@@ -7,7 +7,6 @@ module WeixinRailsMiddleware
|
|
7
7
|
class ReplyMessage
|
8
8
|
include ROXML
|
9
9
|
xml_name :xml
|
10
|
-
#xml_convention :camelcase
|
11
10
|
|
12
11
|
xml_accessor :ToUserName, :cdata => true
|
13
12
|
xml_accessor :FromUserName, :cdata => true
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: weixin_rails_middleware
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- lanrion
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -111,12 +111,15 @@ files:
|
|
111
111
|
- lib/generators/weixin_rails_middleware/install_generator.rb
|
112
112
|
- lib/generators/weixin_rails_middleware/migration_generator.rb
|
113
113
|
- lib/weixin_rails_middleware.rb
|
114
|
+
- lib/weixin_rails_middleware/adapter.rb
|
115
|
+
- lib/weixin_rails_middleware/adapter/multiple_public_account.rb
|
116
|
+
- lib/weixin_rails_middleware/adapter/single_public_account.rb
|
117
|
+
- lib/weixin_rails_middleware/adapter/weixin_adapter.rb
|
114
118
|
- lib/weixin_rails_middleware/configuration.rb
|
115
119
|
- lib/weixin_rails_middleware/engine.rb
|
116
120
|
- lib/weixin_rails_middleware/helpers/auto_generate_weixin_token_secret_key.rb
|
117
121
|
- lib/weixin_rails_middleware/helpers/reply_weixin_message_helper.rb
|
118
122
|
- lib/weixin_rails_middleware/helpers/unique_token_helper.rb
|
119
|
-
- lib/weixin_rails_middleware/helpers/weixin_authorize_helper.rb
|
120
123
|
- lib/weixin_rails_middleware/models/message.rb
|
121
124
|
- lib/weixin_rails_middleware/models/reply_message.rb
|
122
125
|
- lib/weixin_rails_middleware/version.rb
|
@@ -1,74 +0,0 @@
|
|
1
|
-
module WeixinRailsMiddleware
|
2
|
-
module WeixinAuthorizeHelper
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
protected
|
6
|
-
|
7
|
-
def check_weixin_params
|
8
|
-
|
9
|
-
# if config weixin token string
|
10
|
-
if weixin_token_string.present?
|
11
|
-
if !is_weixin_secret_string_valid?
|
12
|
-
puts "WeixinSecretStringNotMatch"
|
13
|
-
render text: "WeixinSecretStringNotMatch", status: 403
|
14
|
-
return false
|
15
|
-
end
|
16
|
-
# if use database to store public_account
|
17
|
-
else
|
18
|
-
if !is_weixin_secret_key_valid?
|
19
|
-
puts "RecordNotFound"
|
20
|
-
render text: "RecordNotFound - Couldn't find #{token_model} with weixin_secret_key=#{current_weixin_secret_key} ", status: 404
|
21
|
-
return false
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
if !is_signature_valid?
|
26
|
-
puts "WeixinSignatureNotMatch"
|
27
|
-
render text: "WeixinSignatureNotMatch", status: 403
|
28
|
-
return false
|
29
|
-
end
|
30
|
-
true
|
31
|
-
end
|
32
|
-
|
33
|
-
# check the token from Weixin Service is exist in local store.
|
34
|
-
def is_weixin_secret_key_valid?
|
35
|
-
if weixin_token_string.blank?
|
36
|
-
current_weixin_public_account.present?
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def is_weixin_secret_string_valid?
|
41
|
-
current_weixin_secret_key == weixin_secret_string
|
42
|
-
end
|
43
|
-
|
44
|
-
def is_signature_valid?
|
45
|
-
signature = params[:signature] || ''
|
46
|
-
timestamp = params[:timestamp] || ''
|
47
|
-
nonce = params[:nonce] || ''
|
48
|
-
sort_params = [current_weixin_token, timestamp, nonce].sort.join
|
49
|
-
current_signature = Digest::SHA1.hexdigest(sort_params)
|
50
|
-
return true if current_signature == signature
|
51
|
-
false
|
52
|
-
end
|
53
|
-
|
54
|
-
def current_weixin_secret_key
|
55
|
-
@weixin_secret_key = params[:weixin_secret_key]
|
56
|
-
end
|
57
|
-
|
58
|
-
def current_weixin_token
|
59
|
-
return weixin_token_string if weixin_token_string.present?
|
60
|
-
current_weixin_public_account.try(DEFAULT_TOKEN_COLUMN_NAME)
|
61
|
-
end
|
62
|
-
|
63
|
-
def current_weixin_public_account
|
64
|
-
@current_weixin_public_account = token_model_class.where("#{DEFAULT_WEIXIN_SECRET_KEY}" => current_weixin_secret_key).first
|
65
|
-
end
|
66
|
-
|
67
|
-
# return a message class with current_weixin_params
|
68
|
-
def current_weixin_message
|
69
|
-
Message.factory(request.body.read)
|
70
|
-
end
|
71
|
-
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|