From 7125e71563179bfd416496f0fa99a1e851a5eeae Mon Sep 17 00:00:00 2001 From: p31729568 Date: Wed, 16 Oct 2019 10:53:37 +0800 Subject: [PATCH] weapp api --- app/controllers/weapps/base_controller.rb | 34 ++++++++++ .../weapps/code_sessions_controller.rb | 24 +++++++ .../weapps/registers_controller.rb | 63 +++++++++++++++++++ app/controllers/weapps/sessions_controller.rb | 24 +++++++ app/controllers/weapps/verifies_controller.rb | 8 +++ app/libs/wechat/weapp.rb | 38 ++++++++++- config/configuration.yml.example | 3 + config/initializers/wechat_init.rb | 8 +++ config/routes.rb | 7 +++ 9 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 app/controllers/weapps/base_controller.rb create mode 100644 app/controllers/weapps/code_sessions_controller.rb create mode 100644 app/controllers/weapps/registers_controller.rb create mode 100644 app/controllers/weapps/sessions_controller.rb create mode 100644 app/controllers/weapps/verifies_controller.rb diff --git a/app/controllers/weapps/base_controller.rb b/app/controllers/weapps/base_controller.rb new file mode 100644 index 000000000..fadf10fb6 --- /dev/null +++ b/app/controllers/weapps/base_controller.rb @@ -0,0 +1,34 @@ +class Weapps::BaseController < ApplicationController + + private + + def require_wechat_login! + return if session_unionid.present? + + render_error('请先进行微信授权') + end + + def weapp_session_key + Wechat::Weapp.session_key(session_openid) + end + + def set_weapp_session_key(session_key) + Wechat::Weapp.write_session_key(session_openid, session_key) + end + + def session_openid + session[:openid] + end + + def set_session_openid(openid) + session[:openid] = openid + end + + def session_unionid + session[:unionid] + end + + def set_session_unionid(unionid) + session[:unionid] = unionid + end +end \ No newline at end of file diff --git a/app/controllers/weapps/code_sessions_controller.rb b/app/controllers/weapps/code_sessions_controller.rb new file mode 100644 index 000000000..7c1978e5f --- /dev/null +++ b/app/controllers/weapps/code_sessions_controller.rb @@ -0,0 +1,24 @@ +class Weapps::CodeSessionsController < Weapps::BaseController + def create + return render_error('code不能为空') if params[:code].blank? + + result = Wechat::Weapp.jscode2session(params[:code]) + + set_session_openid(result['openid']) + set_weapp_session_key(result['session_key']) # weapp session_key写入缓存 后续解密需要 + + # 已授权,绑定过账号 + open_user = OpenUser::Wechat.find_by(uid: result['unionid']) + if open_user.present? && open_user.user + set_session_unionid(result['unionid']) + successful_authentication(open_user.user) + else + # 新用户 + user_info = Wechat::Weapp.decrypt(result['session_key'], params[:encrypted_data], params[:iv]) + + set_session_unionid(user_info['unionId']) + end + + render_ok(openid: result['openid']) + end +end \ No newline at end of file diff --git a/app/controllers/weapps/registers_controller.rb b/app/controllers/weapps/registers_controller.rb new file mode 100644 index 000000000..0cbab7fd4 --- /dev/null +++ b/app/controllers/weapps/registers_controller.rb @@ -0,0 +1,63 @@ +class Weapps::RegistersController < Weapps::BaseController + before_action :require_wechat_login! + + def create + # 查询验证码是否正确;type只可能是1或者8 + type = phone_mail_type(params[:login].strip) + code = params[:code].strip + + if type == 1 + uid_logger("start register by phone: type is #{type}") + pre = 'p' + email = nil + phone = params[:login] + verifi_code = VerificationCode.where(phone: phone, code: code, code_type: 1).last + else + uid_logger("start register by email: type is #{type}") + pre = 'm' + email = params[:login] + phone = nil + verifi_code = VerificationCode.where(email: email, code: code, code_type: 8).last + end + uid_logger("start register: verifi_code is #{verifi_code}, code is #{code}, time is #{Time.now.to_i - verifi_code.try(:created_at).to_i}") + # check_code = (verifi_code.try(:code) == code.strip && (Time.now.to_i - verifi_code.created_at.to_i) <= 10*60) + # todo 上线前请删除万能验证码"513231" + unless code == "513231" && request.subdomain == "test-newweb" + return render_error('验证码不正确') if verifi_code.try(:code) != code.strip + return render_error('验证码已失效') if !verifi_code&.effective? + end + + login = User.generate_login(pre) + @user = User.new(admin: false, login: login, mail: email, phone: phone, type: 'User') + @user.password = params[:password] + # 现在因为是验证码,所以在注册的时候就可以激活 + @user.activate + # 必须要用save操作,密码的保存是在users中 + ActiveRecord::Base.transaction do + @user.save! + UserExtension.create!(user_id: @user.id) + # 绑定微信号 + OpenUsers::Wechat.create!(user: @user, uid: session_unionid) + + # 注册完成,手机号或邮箱想可以奖励500金币 + RewardGradeService.call( + @user, + container_id: @user.id, + container_type: pre == 'p' ? 'Phone' : 'Mail', + score: 500 + ) + end + successful_authentication(@user) + session[:user_id] = @user.id + + render_ok + end + + private + + # 1 手机类型;0 邮箱类型 + # 注意新版的login是自动名生成的 + def phone_mail_type value + value =~ /^1\d{10}$/ ? 1 : 0 + end +end \ No newline at end of file diff --git a/app/controllers/weapps/sessions_controller.rb b/app/controllers/weapps/sessions_controller.rb new file mode 100644 index 000000000..f65111399 --- /dev/null +++ b/app/controllers/weapps/sessions_controller.rb @@ -0,0 +1,24 @@ +class Weapps::SessionsController < Weapps::BaseController + before_action :require_wechat_login! + + def create + return render_error('重复登录') if current_user.present? && current_user.logged? + + user = User.try_to_login(params[:login], params[:password]) + + return render_error('错误的账号或密码') if user.blank? + return render_error('违反平台使用规范,账号已被锁定') if user.locked? + return render_error('错误的账号或密码') unless user.check_password?(params[:password].to_s) + + if user.wechat_open_user && user.wechat_open_user.uid != session_unionid + render_error('该账号已被其它微信号绑定') + return + end + + # 绑定微信号 + OpenUsers::Wechat.create!(user: user, uid: session_unionid) if user.wechat_open_user.blank? + + successful_authentication(user) + render_ok + end +end \ No newline at end of file diff --git a/app/controllers/weapps/verifies_controller.rb b/app/controllers/weapps/verifies_controller.rb new file mode 100644 index 000000000..5d8f4056e --- /dev/null +++ b/app/controllers/weapps/verifies_controller.rb @@ -0,0 +1,8 @@ +class Weapps::VerifiesController < Weapps::BaseController + before_action :require_wechat_login! + + def create + valid = Wechat::Weapp.verify?(session_openid, params[:verify_string], params[:signature]) + render_ok(valid: valid) + end +end \ No newline at end of file diff --git a/app/libs/wechat/weapp.rb b/app/libs/wechat/weapp.rb index 54f60fa2a..755c9351a 100644 --- a/app/libs/wechat/weapp.rb +++ b/app/libs/wechat/weapp.rb @@ -1,4 +1,4 @@ -class Wechat::App +class Wechat::Weapp class << self attr_accessor :appid, :secret @@ -7,5 +7,41 @@ class Wechat::App def client @_client ||= Wechat::Client.new(appid, secret) end + + def session_key(openid) + Rails.cache.read(session_key_cache_key(openid)) + end + + def write_session_key(openid, session_key) + Rails.cache.write(session_key_cache_key(openid), session_key) + end + + def verify?(openid, str, signature) + session_key = session_key(openid) + Digest::SHA1.hexdigest("#{str}#{session_key}") == signature + end + + def decrypt(session_key, encrypted_data, iv) + session_key = Base64.decode64(session_key) + encrypted_data = Base64.decode64(encrypted_data) + iv = Base64.decode64(iv) + + cipher = OpenSSL::Cipher::AES.new(128, :CBC) + cipher.decrypt + cipher.padding = 0 + cipher.key = session_key + cipher.iv = iv + data = cipher.update(encrypted_data) << cipher.final + result = JSON.parse(data[0...-data.last.ord]) + + raise Wechat::Error, '解密错误' if result.dig('watermark', 'appid') != appid + result + end + + private + + def session_key_cache_key(openid) + "weapp:#{appid}:#{openid}:session_key" + end end end \ No newline at end of file diff --git a/config/configuration.yml.example b/config/configuration.yml.example index 612011a7f..6ead04a54 100644 --- a/config/configuration.yml.example +++ b/config/configuration.yml.example @@ -18,6 +18,9 @@ defaults: &defaults wechat: appid: 'test' secret: 'test' + weapp: + appid: 'test' + secret: 'test' development: <<: *defaults diff --git a/config/initializers/wechat_init.rb b/config/initializers/wechat_init.rb index 946e5f638..3fd8f9485 100644 --- a/config/initializers/wechat_init.rb +++ b/config/initializers/wechat_init.rb @@ -1,9 +1,12 @@ wechat_config = {} +weapp_config = {} begin config = Rails.application.config_for(:configuration) wechat_config = config['wechat'] + weapp_config = config['weapp'] raise 'wechat config missing' if wechat_config.blank? + raise 'weapp config missing' if weapp_config.blank? rescue => ex raise ex if Rails.env.production? @@ -12,5 +15,10 @@ rescue => ex wechat_config = {} end +# 网站应用 Wechat::OfficialAccount.appid = wechat_config['appid'] Wechat::OfficialAccount.secret = wechat_config['secret'] + +# 小程序 +Wechat::Weapp.appid = weapp_config['appid'] +Wechat::Weapp.secret = weapp_config['secret'] diff --git a/config/routes.rb b/config/routes.rb index 605ae4194..1ef62c0e6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -829,6 +829,13 @@ Rails.application.routes.draw do get '/auth/qq/callback', to: 'oauth/qq#create' get '/auth/wechat/callback', to: 'oauth/wechat#create' resource :bind_user, only: [:create] + + namespace :weapps do + resource :session, only: [:create] + resource :register, only: [:create] + resource :code_session, only: [:create] + resource :verify, only: [:create] + end end namespace :admins do