1.首先定义一个action 和 一个路由 这个路由可以是 POST/GET 请求。

resources :work_wechat do
  collection do
    match :notify, via: [:get, :post]
  end
end

在对应的controller.rb文件中,添加如下:

before_action :verify_sign?

def notify
  begin
  	# 得到请求体
    request_xml = request.body.read
    if request_xml.present?
      # 将xml格式转换为Hash格式
      notify_hash = Hash.from_xml(request_xml)['xml']
      # 解密密文 得到请求体
      request_xml, @status = aes_decrypt(notify_hash["Encrypt"])
      Rails.logger.info("-----------打印解密的密文: #{request_xml}-------------")
      decrypt_xml = Hash.from_xml(request_xml)
      # 执行方法(自定义)这里是回调成功后要做的任务(这里推荐异步去执行,因为企业微信1秒内需要得到返回码,否则企业微信将会在发送3次后终止)
      WorkWechat.perform_task(decrypt_xml)
    end
  rescue => exception
    @status = 500
    Rails.logger.info "------企业微信解密失败: #{exception.message}------"
    SaasLog.info({content: "企业微信解密失败: #{exception.message}", params: "work_wechat_verify_sign"})
  end
  render plain: @content, status: @status

private
  # 验签 具体解密的步骤可以参考企业微信的开发文档: [回调需要哪些配置](https://work.weixin.qq.com/api/doc/90000/90135/90930#2.%20%E5%9B%9E%E8%B0%83%E6%9C%8D%E5%8A%A1%E9%9C%80%E8%A6%81%E5%93%AA%E4%BA%9B%E9%85%8D%E7%BD%AE)
  def verify_sign?
    # 加密算法
    token = Settings.work_wechat.token
    timestamp         = params[:timestamp]
    nonce             = params[:nonce]
    echo_str          = params[:echostr]
    msg_signature     = params[:msg_signature]
    sort_params = [token, timestamp, nonce, echo_str].compact.sort.join
    if valid_msg_signature(sort_params, msg_signature)
      @content, @status = aes_decrypt(echo_str)
    end
  end

  def valid_msg_signature(sort_params, msg_signature)
    current_signature = Digest::SHA1.hexdigest(sort_params)
    Rails.logger.info("current_signature: #{current_signature} ")
    ActiveSupport::SecurityUtils.secure_compare(current_signature, msg_signature)
  end

  def aes_decrypt(str)
    encoding_aes_key = Settings.work_wechat.encoding_aes_key
    aes_key = Base64.decode64(encoding_aes_key + "=")
    WorkWechat.decrypt(aes_key, str)
  end
end

3.封装方法类

class << WorkWatch
  class << self
	def handle_cipher(action, aes_key, text)
	  # 使用AES::256::CBC模式解密
      cipher = OpenSSL::Cipher.new('AES-256-CBC')
      cipher.send(action)
      cipher.padding = 0
      cipher.key     = aes_key
      cipher.iv      = aes_key[0...16]
      cipher.update(text) + cipher.final
    end

    # 对密文进行解密.
    # text 需要解密的密文 corpid不传默认返回状态码200
    def decrypt(aes_key, text, corpid=nil)
      status = 200
      text        = Base64.decode64(text)
      text        = handle_cipher(:decrypt, aes_key, text)
      result      = pkcs_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]
      # 状态码
      if corpid.present? && corpid != from_corpid
        Rails.logger.info("企业微信回调验签失败 #{corpid} != #{from_corpid}")
        status = 401
      end
      [xml_content, status]
    end

    # 加密
    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    = pkcs_encode(text)
      text    = handle_cipher(:encrypt, aes_key, text)
      Base64.encode64(text)
    end
	
	# 企业微信的要求 取解密后的第N位
    def pkcs_decode(text)
      pad = text[-1].ord
      pad = 0 if (pad < 1 || pad > 32)
      size = text.size - pad
      text[0...size]
    end

    # 对需要加密的明文进行填充补位
    # 返回补齐明文字符串
    def pkcs_encode(text)
      # 计算需要填充的位数
      amount_to_pad = 32 - (text.length % 32)
      amount_to_pad = 32 if amount_to_pad == 0
      # 获得补位所用的字符
      pad_chr = amount_to_pad.chr
      "#{text}#{pad_chr * amount_to_pad}"
    end
  end
end

4.如果你在开发环境下 想测试企业微信回调的地址,首先要自己注册一个企业微信的账号或者用其他账号。以下是本地测试的方法,经测试可用:

需要新建一个 ngrok.yml 的文件,我这里名称给的 test,你们自定义吧,内容如下

authtoken:
tunnels:
  test:
    proto: http
    addr: 3001
内网穿透 ngrok 下载地址:https://dashboard.ngrok.com/get-started/setup 1.首先登陆 注册账号 2.进入Your Authtoken 将秘钥CORY 保留 3.将下载的文件拷贝到bin目录下 命令: cp /Users/ai/Downloads/ngrok /usr/local/bin/ 4.在终端首页 mkdir .ngrok2 的一个文件夹 5.将配置文件cp到ngrok2文件夹下 ‘cp 文件路径 .ngrok2’ 6.编辑文件 不要cd,vim .ngrok2/ngrok.yml 7.将authtoken:后加上: 空格和拷贝的秘钥(注意前边加空格) 8.addr是配置的端口,可以配置多个 但是不能重复 9.启动 ngrok start test,启动后结果如下,返回的localhost:3000 以及随机的外网地址(Forwarding 就是需要的外网地址,拿过去配置企业微信API回调的服务器就行了)

springboot 企业微信服务商回调 企业微信回调配置_ci

10.请求外网地址将返回的错误信息如(config.hosts << “147b-42-84-33-20.ngrok.io”)放到项目config/application.rb文件夹下
11.重启服务