這塊我在8月17號的時候碰到過,再回調模式初步驗證通過以後,微信服務器後續的信息會由原來的msg_signature. timestamp. nonce. echostr改爲3個參數msg_signature. timestamp. nonce以及一串 xml信息,少了第四個參數,而簽名驗證的生成又必須要用到第4個參數echostr,否則單一的用timestamp. nonce. token生成的signature會跟接收的msg_signature不一致,導致驗證是否爲微信服務器發送的消息失敗。
因此我們必須自己通過解讀xml裏的參數Encrypt拿到echostr來加入簽名字符串的加密生成,同時也可以拿到其他解密後的xml信息生成一個hashmap進行後續的開發應用:
#@msg_encrypt就是我們要的Encrypt
# 加密
def encrypt(aes_key, text, corpid)
text = text.force_encoding("ASCII-8BIT")
random = SecureRandom.hex(8)
msg_len = [text.length].pack("N")
text = "#{random}#{msg_len}#{text}#{corpid}"
text = encode(text)
text = handle_cipher(:encrypt, aes_key, text)
Base64.encode64(text)
end
# 對密文進行解密.
# text 需要解密的密文
def decrypt(aes_key, text, corpid)
status = 200
text = Base64.decode64(text)
text = handle_cipher(:decrypt, aes_key, text)
result = decode(text)
content = result[16...result.length]
len_list = content[0...4].unpack("N")
xml_len = len_list[0]
xml_content = content[4...4 + xml_len]
from_corpid = content[xml_len+4...content.size]
# TODO: refactor
if corpid != from_corpid
Rails.logger.debug("#{__FILE__}:#{__LINE__} Failure because #{corpid} != #{from_corpid}")
status = 401
end
[xml_content, status]
end
# 對需要加密的明文進行填充補位
# 返回補齊明文字符串
def encode(text)
# 計算需要填充的位數
amount_to_pad = @BLOCK_SIZE - (text.length % @BLOCK_SIZE)
amount_to_pad = @BLOCK_SIZE if amount_to_pad == 0
# 獲得補位所用的字符
pad_chr = amount_to_pad.chr
"#{text}#{pad_chr * amount_to_pad}"
end
def setup_wechat_message
wx = Wx.new
# Rails.logger.debug("encoding_aes_key: #{encoding_aes_key}, qy_token: #{qy_token}, corp_id: #{corp_id}")
param_xml = request.body.read
hash = MultiXml.parse(param_xml)['xml']
@msg_encrypt = hash["Encrypt"]
@body_xml = OpenStruct.new(hash)
@content = decrypt(aes_key, @body_xml.Encrypt, corp_id)[0]
@hash = MultiXml.parse(@content)["xml"]
end