这块我在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