lib/wechat/controller_api.rb
# frozen_string_literal: true
module Wechat
module ControllerApi
extend ActiveSupport::Concern
module ClassMethods
attr_accessor :wechat_api_client, :wechat_cfg_account, :token, :appid, :corpid, :agentid, :encrypt_mode, :timeout,
:skip_verify_ssl, :encoding_aes_key, :trusted_domain_fullname, :oauth2_cookie_duration
end
def wechat(account = nil)
# Make sure user can continue access wechat at instance level similar to class level
self.class.wechat(account)
end
def wechat_oauth2(scope = 'snsapi_base', page_url = nil, account = nil, &block)
# ensure wechat initialization
self.class.corpid || self.class.appid || self.class.wechat
api = wechat(account)
if account
config = Wechat.config(account)
appid = config.corpid || config.appid
is_crop_account = config.corpid.present?
else
appid = self.class.corpid || self.class.appid
is_crop_account = self.class.corpid.present?
end
raise 'Can not get corpid or appid, so please configure it first to using wechat_oauth2' if appid.blank?
oauth2_params = {
appid: appid,
redirect_uri: page_url || generate_redirect_uri(account),
scope: scope,
response_type: 'code',
state: api.jsapi_ticket.oauth2_state
}
return generate_oauth2_url(oauth2_params) unless block_given?
is_crop_account ? wechat_corp_oauth2(oauth2_params, account, &block) : wechat_public_oauth2(oauth2_params, account, &block)
end
private
def wechat_public_oauth2(oauth2_params, account = nil)
openid = cookies.signed_or_encrypted[:we_openid]
unionid = cookies.signed_or_encrypted[:we_unionid]
we_token = cookies.signed_or_encrypted[:we_access_token]
if openid.present?
yield openid, { 'openid' => openid, 'unionid' => unionid, 'access_token' => we_token }
elsif params[:code].present? && params[:state] == oauth2_params[:state]
access_info = wechat(account).web_access_token(params[:code])
cookies.signed_or_encrypted[:we_openid] = { value: access_info['openid'], expires: (Time.now + self.class.oauth2_cookie_duration) }
cookies.signed_or_encrypted[:we_unionid] = { value: access_info['unionid'], expires: (Time.now + self.class.oauth2_cookie_duration) }
cookies.signed_or_encrypted[:we_access_token] = { value: access_info['access_token'], expires: (Time.now + self.class.oauth2_cookie_duration) }
yield access_info['openid'], access_info
else
redirect_to generate_oauth2_url(oauth2_params), allow_other_host: true
end
end
def wechat_corp_oauth2(oauth2_params, account = nil)
userid = cookies.signed_or_encrypted[:we_userid]
deviceid = cookies.signed_or_encrypted[:we_deviceid]
if userid.present? && deviceid.present?
yield userid, { 'UserId' => userid, 'DeviceId' => deviceid }
elsif params[:code].present? && params[:state] == oauth2_params[:state]
userinfo = wechat(account).getuserinfo(params[:code])
cookies.signed_or_encrypted[:we_userid] = { value: userinfo['UserId'], expires: (Time.now + self.class.oauth2_cookie_duration) }
cookies.signed_or_encrypted[:we_deviceid] = { value: userinfo['DeviceId'], expires: (Time.now + self.class.oauth2_cookie_duration) }
yield userinfo['UserId'], userinfo
else
redirect_to generate_oauth2_url(oauth2_params), allow_other_host: true
end
end
def generate_redirect_uri(account = nil)
domain_name = if account
Wechat.config(account).trusted_domain_fullname
else
self.class.trusted_domain_fullname
end
page_url = domain_name ? "#{domain_name}#{request.original_fullpath}" : request.original_url
safe_query = request.query_parameters.reject { |k, _| %w[code state access_token].include? k }.to_query
page_url.sub(request.query_string, safe_query)
end
def generate_oauth2_url(oauth2_params)
if oauth2_params[:scope] == 'snsapi_login'
"https://open.weixin.qq.com/connect/qrconnect?#{oauth2_params.to_query}#wechat_redirect"
else
"https://open.weixin.qq.com/connect/oauth2/authorize?#{oauth2_params.to_query}#wechat_redirect"
end
end
end
end