REST APIによるスパム対策とCAPTCHAのサポート
モデルを REST API 経由で変更できる場合、スパム可能な属性やスパム関連の属性を変更する可能性のある、関連する API エンドポイントすべてにサポートを追加しなければなりません。これにはPOST
とPUT
の変異が間違いなく含まれますが、モデルの機密/公開フラグの変更に関するものなど、他のものも含まれるかもしれません。
RESTエンドポイントへのサポートの追加
主な手順は以下の通りです:
-
resource
にhelpers SpammableActions::CaptchaCheck::RestApiActionsSupport
を追加します。 - Update Service クラスのコンストラクタに
perform_spam_check: true
を渡します。Create Serviceでは、デフォルトでtrue
。 -
Spammable
モデル・インスタンスを作成または更新したら、#check_spam_action_response!
を呼び出し、作成または更新されたインスタンスを変数に保存します。 - 作成または更新が成功しなかったリクエストの
failure
ケースのエラー処理ロジックを特定します。これらは、Spammable
インスタンスにエラーを追加する、スパム検出の可能性を示します。エラーは通常、render_api_error!
またはrender_validation_error!
に似ています。 - 既存のエラー処理ロジックを
with_captcha_check_rest_api(spammable: my_spammable_instance)
呼び出しでラップし、変数に保存したSpammable
モデルインスタンスをspammable:
の名前付き引数として渡します。この呼び出しは- モデルに必要なスパムチェックを実行します。
- スパムが検出された場合
- スパム特有のエラーメッセージとともに、Grape
#error!
例外を発生させます。 - エラーフィールドとして追加された関連情報をレスポンスに含めます。これらのフィールドの詳細については、REST API ドキュメントの「Resolve requests detected as spam」のセクションを参照してください。
- スパム特有のエラーメッセージとともに、Grape
上記の標準的なApolloLinkまたはAxiosインターセプターのCAPTCHAサポートを使用する場合、フィールドの詳細は自動的に処理されるため、無視することができます。これらは、GraphQL APIを直接使用して潜在的なスパムのチェックに失敗した処理を行い、解決されたCAPTCHAレスポンスでリクエストを再送信しようとした場合に関係します。
以下はsnippets
リソースに対するpost
とput
アクションの例です:
module API
class Snippets < ::API::Base
#...
resource :snippets do
# This helper provides `#with_captcha_check_rest_api`
helpers SpammableActions::CaptchaCheck::RestApiActionsSupport
post do
#...
service_response = ::Snippets::CreateService.new(project: nil, current_user: current_user, params: attrs).execute
snippet = service_response.payload[:snippet]
if service_response.success?
present snippet, with: Entities::PersonalSnippet, current_user: current_user
else
# Wrap the normal error response in a `with_captcha_check_rest_api(spammable: snippet)` block
with_captcha_check_rest_api(spammable: snippet) do
# If possible spam was detected, an exception would have been thrown by
# `#with_captcha_check_rest_api` for Grape to handle via `error!`
render_api_error!({ error: service_response.message }, service_response.http_status)
end
end
end
put ':id' do
#...
service_response = ::Snippets::UpdateService.new(project: nil, current_user: current_user, params: attrs, perform_spam_check: true).execute(snippet)
snippet = service_response.payload[:snippet]
if service_response.success?
present snippet, with: Entities::PersonalSnippet, current_user: current_user
else
# Wrap the normal error response in a `with_captcha_check_rest_api(spammable: snippet)` block
with_captcha_check_rest_api(spammable: snippet) do
# If possible spam was detected, an exception would have been thrown by
# `#with_captcha_check_rest_api` for Grape to handle via `error!`
render_api_error!({ error: service_response.message }, service_response.http_status)
end
end
end