我正在尝试在我的 rails 5 应用程序中设置 Recaptcha,如文档中所述,但它失败了。
我使用这个宝石:recaptcha(4.6.6),ruby 2.5.0
和rails 5.1.4
在视图形式中:
<%= flash[:recaptcha_error] %>
<%= recaptcha_tags %>
在设计注册控制器中:
prepend_before_action :check_captcha, only: :create
private
def check_captcha
unless verify_recaptcha
self.resource = resource_class.new sign_up_params
resource.validate # Look for any other validation errors besides Recaptcha
respond_with_navigational(resource) { redirect_to new_user_registration_path }
end
end
在我的初始化器/recaptcha.rb 中
Recaptcha.configure do |config|
config.site_key = Rails.application.config_for(:recaptcha)['site_key']
config.secret_key = Rails.application.config_for(:recaptcha)['secret_key']
end
在我的验证码.yml中:
default: &default
site_key: <%= ENV["RECAPTCHA_SITE_KEY"] %>
secret_key: <%= ENV["RECAPTCHA_SECRET_KEY"] %>
development:
<<: *default
test:
<<: *default
staging:
<<: *default
production:
<<: *default
在/etc/环境中:
# RECAPTCHA
RECAPTCHA_SITE_KEY=6Lfg3ksUAAAAABOD_OXCtPO60*******
RECAPTCHA_SECRET_KEY=6Lfg3ksUAAAAAOmFGdAxdo8*******
问题
将 ENV 变量添加到/etc/environments
后,我用以下命令将其导出:
for line in $( cat /etc/environment ) ; do export $line ; done
然后我检查验证码模块配置是否正确:
/home/deploy/apps/app_name/current$ bundle exec rails c
Loading staging environment (Rails 5.1.4)
2.5.0 :001 > Recaptcha::Configuration.new
=> #<Recaptcha::Configuration:0x0000000006601908 @skip_verify_env=["test", "cucumber"], @handle_timeouts_gracefully=true, @secret_key="6Lfg3ksUAAAAAOmFGdAxdo8H*************", @site_key="6Lfg3ksUAAAAABOD_OXCtPO*************">
2.5.0 :002 > Recaptcha::Configuration.new.site_key!
=> "6Lfg3ksUAAAAABOD_OXCtPO*************"
另外,当我运行printenv
命令时,我看到了这些 ENV 变量(所以它真的加载了)
之后,我重新启动了轨道并得到了一个错误
未指定站点密钥。
/home/deploy/apps/app_name/shared/bundle/ruby/2.5.0/gems/recaptcha-4.6.6/lib/recaptcha/configuration.rb:47:in `site_key!'
/home/deploy/apps/app_name/shared/bundle/ruby/2.5.0/gems/recaptcha-4.6.6/lib/recaptcha/client_helper.rb:79:in `recaptcha_components'
/home/deploy/apps/app_name/shared/bundle/ruby/2.5.0/gems/recaptcha-4.6.6/lib/recaptcha/client_helper.rb:15:in `recaptcha_tags'
/home/deploy/apps/app_name/releases/20180310222304/app/views/users/registrations/new.html.erb:27:in `block in _app_views_users_registrations_new_html_erb___216558772140569572_69973306795360'
/home/deploy/apps/app_name/shared/bundle/ruby/2.5.0/gems/actionview-5.1.4/lib/action_view/helpers/capture_helper.rb:39:in `block in capture'
/home/deploy/apps/app_name/shared/bundle/ruby/2.5.0/gems/actionview-5.1.4/lib/action_view/helpers/capture_helper.rb:203:in `with_output_buffer'
/home/deploy/apps/app_name/shared/bundle/ruby/2.5.0/gems/actionview-5.1.4/lib/action_view/helpers/capture_helper.rb:39:in `capture'
/home/deploy/apps/app_name/shared/bundle/ruby/2.5.0/gems/actionview-5.1.4/lib/action_view/helpers/form_helper.rb:450:in `form_for'
/home/deploy/apps/app_name/releases/20180310222304/app/views/users/registrations/new.html.erb:21:in `_app_views_users_registrations_new_html_erb___216558772140569572_69973306795360'
/home/deploy/apps/app_name/shared/bundle/ruby/2.5.0/gems/actionview-5.1.4/lib/action_view/template.rb:157:in `block in render'
我在这里发帖,以防有人正在寻找设置 Recaptcha 密钥的 Rails 5.2 解决方案。该解决方案利用新的config/master.key和config/credentials.yml.enc加密文件。
-
通过在本地终端中编辑 credentials.yml.enc 文件,将 Recaptcha 密钥添加到该文件:
EDITOR="vim" rails credentials:edit
-
将密钥添加到凭证文件(请参阅下面的示例)后,保存并退出该文件。退出后,凭据.yml.enc文件将自动加密。主密钥是应用程序解密所必需的。加密前:
recaptcha_site_key: 6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy recaptcha_secret_key: 6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxx
3. 在 Rails 应用程序中创建一个名为 config/recaptcha.rb 的文件,并向其中添加以下代码:
Recaptcha.configure do |config|
config.site_key = Rails.application.credentials.dig(:recaptcha_site_key)
config.secret_key = Rails.application.credentials.dig(:recaptcha_secret_key)
end
该解决方案在本地和生产中的Ubuntu/nginx上运行。您不需要 gem 或环境变量即可使其正常工作。如果 master.key 解密失败,您可能需要删除 credentials.yml.enc 文件,甚至可能需要删除 master.key 文件,然后在将新的 master.key 复制到生产环境并重新部署之前,在本地重复此过程(EDITOR="vim" rails credentials:edit 等)。
我仍然不知道"未指定站点密钥"错误的原因是什么。
我真的不喜欢gem 'recapthca'
直接使用 ENV 变量,
而且我在调查上花了太多时间。
因此,我决定不使用这个 gem 并编写自己的代码。
我在应用程序中只使用隐形验证码。
配置文件(加载机密密钥和站点密钥)
# /config/recaptcha.yml
default: &default
site_key: <%= ENV["RECAPTCHA_SITE_KEY"] %>
secret_key: <%= ENV["RECAPTCHA_SECRET_KEY"] %>
development:
<<: *default
test:
<<: *default
staging:
<<: *default
production:
<<: *default
应用程序助手(带有 Recaptcha 助手的按钮)
# /app/helpers/application_helper.rb
module ApplicationHelper
def submit_with_recaptcha(text, custom_options)
unless custom_options[:data].has_key?(:form_id)
raise "Data Form Id option not found ('{data: {form_id: 'id_without_dash'}')."
end
options = {
type: 'button',
data: {
form_id: custom_options[:data][:form_id],
sitekey: recaptcha_site_key,
callback: "submit#{custom_options[:data][:form_id].camelize}#{Time.current.to_i}"
},
class: (custom_options[:class].split(' ') + ['g-recaptcha']).uniq.join(' ')
}
script_code = <<-SCRIPT
function #{options[:data][:callback]}() {
document.getElementById('#{options[:data][:form_id]}').submit();
}
SCRIPT
javascript_tag(script_code) + content_tag(:div, class: 'recaptcha_wrapper'){ submit_tag(text, options) }
end
private
def recaptcha_site_key
Rails.application.config_for(:recaptcha)['site_key']
end
end
验证服务(因为它使用外部 API)
# app/services/google_recaptcha/verification.rb
module GoogleRecaptcha
# https://developers.google.com/recaptcha/docs/verify
class Verification
# response - params['g-recaptcha-response'])
def self.successful?(recaptcha_params, remoteip)
verify_url = URI.parse('https://www.google.com/recaptcha/api/siteverify')
verify_request = Net::HTTP::Post.new(verify_url.path)
verify_request.set_form_data(
response: recaptcha_params,
secret: secret_key,
remoteip: remoteip
)
connection = Net::HTTP.new(verify_url.host, verify_url.port)
connection.use_ssl = true
Rails.logger.info '[RECAPTCHA] Sending verification request.'
verify_response = connection.start { |http| http.request(verify_request) }
response_data = JSON.parse(verify_response.body)
Rails.logger.info "[RECAPTCHA] Verification response is#{' not' unless response_data['success']} successful."
response_data['success']
end
private
def self.secret_key
Rails.application.config_for(:recaptcha)['secret_key']
end
end
end
控制器问题(before_action 中的验证码验证)
# app/controllers/concerns/recaptchable.rb
module Recaptchable
extend ActiveSupport::Concern
included do
before_action :verify_recaptcha, only: [:create]
end
private
def verify_recaptcha
unless GoogleRecaptcha::Verification.successful?(recaptcha_params['g-recaptcha-response'], request.remote_ip)
render :new
return
end
end
def recaptcha_params
params.permit(:'g-recaptcha-response')
end
end
用法
向控制器添加关注点:
class MyController < ShopController
include Recaptchable
end
将www.google.com/recaptcha/api.js
JavaScript 添加到您的页面
将submit_with_recaptcha
帮助程序添加到表单中
<%= form_for @delivery, url: users_delivery_path, method: 'post' do |f| %>
<%= submit_with_recaptcha t('order.deliver.to_confirmation'), data: {form_id: 'new_delivery'}, class: 'btn-round' %>
<% end %>
<%= javascript_include_tag "https://www.google.com/recaptcha/api.js?hl=#{I18n.locale}", 'data-turbolinks-track': 'reload' %>
就是这样。
注意:我在这里发布这个答案,供可能发现这个问题的人使用。这是我解决问题的方法。
我使用 local_env.yml 作为我的环境变量。我刚刚开始使用宝石,并将RECAPTCHA_SITE_KEY & RECAPTCHA_SECRET_KEY添加到 local_env.yml。我得到了同样的错误。
花了一点时间才弄清楚 gem 直接使用了变量。我最终将以下语句放在~/.bashrc
类似于文档所说的,但没有在值周围引号。
export RECAPTCHA_SITE_KEY=6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy
export RECAPTCHA_SECRET_KEY=6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxx
我在 Heroku 上托管我的应用程序。我执行了以下终端命令来在 Heroku 中设置我的环境变量。
heroku config:set RECAPTCHA_SITE_KEY=‘6Lc6BAAAAAAAAChqRbQZcn_yyyyyyyyyyyyyyyyy’
heroku config:set RECAPTCHA_SECRET_KEY=‘6LcGuI4U6Lc6BAAAAAAAAKN3DRm6VA_xxxxxxxxxxxxxxxxxAAAAGAWMYRKFGfHUCSD0SPrMX2lfyl9’
你在用nginx吗?Nginx 删除了 ENV var(TZ 除外),似乎验证码宝石对此特别敏感。根据经验,当使用dotenv
宝石时,其他 ENV 变量工作正常,验证码 ENV 变量将被忽略。
您可以通过将env vars添加到nginx.conf的顶部来解决此问题。
env RECAPTCHA_SITE_KEY=value1;
env RECAPTCHA_SECRET_KEY=value2;
这是nginx关于此事的文档。