SafetyNet reCAPTCHA API

SafetyNet 服务包含一种 reCAPTCHA API,该 API 可用于防止您的应用遭受恶意流量的侵害。

reCAPTCHA 是一项免费服务,它会使用高级风险分析引擎来保护您的应用免受网络垃圾和其他滥用行为的影响。如果该服务怀疑与您的应用互动的用户可能是机器人而非真人,则会提供一项人机识别系统验证,真人必须先通过这一验证,然后您的应用才可以继续执行。

本文档介绍了如何将 SafetyNet 中的 reCAPTCHA API 集成到您的应用中。

附加服务条款

访问或使用 reCAPTCHA API 即表示您同意 Google API 服务条款及这些附加条款。请先阅读并了解所有适用的条款及政策,然后再使用这些 API。

reCAPTCHA 服务条款

您承认并了解,reCAPTCHA API 在运行时会收集各种软硬件信息,例如设备和应用数据以及完整性检查的结果等,并会将这些数据发送给 Google 进行分析。根据“Google API 服务条款”第 3(d) 条的规定,您同意使用这些 API 即表示您负责就收集这类数据以及与 Google 分享这类数据提供任何必要的声明或同意。

注册 reCAPTCHA 密钥对

如需注册用于 SafetyNet reCAPTCHA API 的密钥对,请转到 reCAPTCHA Android 注册网站,然后完成下面这一系列步骤:

  1. 在显示的表单中提供以下信息:

    • 标签:您的密钥的唯一标签。通常情况下,您可以使用公司或单位的名称。
    • 软件包名称:请提供使用此 API 密钥的每个应用的软件包名称。要让应用使用该 API,您输入的软件包名称必须与该应用的软件包名称完全一致。输入时,请将每个软件包名称单独放在一行。
    • 向所有者发出提醒:如果您想接收有关此 reCAPTCHA API 的电子邮件,请选中此复选框。
  2. 选中接受“reCAPTCHA 服务条款”复选框,然后点击注册

  3. 在随即显示的页面中的将 reCAPTCHA 添加到您的应用部分,您可以在网站密钥密钥下分别找到您的公钥和私钥。您可以在发送验证请求时使用网站密钥,在验证用户响应令牌时使用密钥。

添加 SafetyNet API 依赖项

您需要先将 SafetyNet API 添加到您的项目,然后才能使用 reCAPTCHA API。如果您使用的是 Android Studio 并且想要选择性地将此 API 编译到您的 Gradle 依赖项,则您应该添加以下代码段中所示的编译规则:

    apply plugin: 'com.android.application'
    ...
    dependencies {
        compile 'com.google.android.gms:play-services-safetynet:17.0.0'
    }
    

如需了解详情,请参阅设置 Google Play 服务

使用 reCAPTCHA API

本部分介绍了如何调用 reCAPTCHA API 以发送人机识别系统验证请求并接收用户响应令牌。

发送验证请求

要调用 SafetyNet reCAPTCHA API,您需要调用 verifyWithRecaptcha() 方法。通常情况下,此方法与用户在您的 Activity 中选择界面元素(如按钮)相对应。

在您的应用中使用 verifyWithRecaptcha() 方法时,您必须执行以下操作:

以下代码段演示了如何调用此方法:

Kotlin

    fun onClick(view: View) {
        SafetyNet.getClient(this).verifyWithRecaptcha(YOUR_API_SITE_KEY)
                .addOnSuccessListener(this as Executor, OnSuccessListener { response ->
                    // Indicates communication with reCAPTCHA service was
                    // successful.
                    val userResponseToken = response.tokenResult
                    if (response.tokenResult?.isNotEmpty() == true) {
                        // Validate the user response token using the
                        // reCAPTCHA siteverify API.
                    }
                })
                .addOnFailureListener(this as Executor, OnFailureListener { e ->
                    if (e is ApiException) {
                        // An error occurred when communicating with the
                        // reCAPTCHA service. Refer to the status code to
                        // handle the error appropriately.
                        Log.d(TAG, "Error: ${CommonStatusCodes.getStatusCodeString(e.statusCode)}")
                    } else {
                        // A different, unknown type of error occurred.
                        Log.d(TAG, "Error: ${e.message}")
                    }
                })
    }
    

Java

    public void onClick(View v) {
        SafetyNet.getClient(this).verifyWithRecaptcha(YOUR_API_SITE_KEY)
            .addOnSuccessListener((Executor) this,
                new OnSuccessListener<SafetyNetApi.RecaptchaTokenResponse>() {
                    @Override
                    public void onSuccess(SafetyNetApi.RecaptchaTokenResponse response) {
                        // Indicates communication with reCAPTCHA service was
                        // successful.
                        String userResponseToken = response.getTokenResult();
                        if (!userResponseToken.isEmpty()) {
                            // Validate the user response token using the
                            // reCAPTCHA siteverify API.
                        }
                    }
            })
            .addOnFailureListener((Executor) this, new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        if (e instanceof ApiException) {
                            // An error occurred when communicating with the
                            // reCAPTCHA service. Refer to the status code to
                            // handle the error appropriately.
                            ApiException apiException = (ApiException) e;
                            int statusCode = apiException.getStatusCode();
                            Log.d(TAG, "Error: " + CommonStatusCodes
                                    .getStatusCodeString(statusCode));
                        } else {
                            // A different, unknown type of error occurred.
                            Log.d(TAG, "Error: " + e.getMessage());
                        }
                    }
            });
    }
    

验证用户响应令牌

如果 reCAPTCHA API 执行 onSuccess() 方法,则表示用户已成功完成人机识别系统验证。不过,此方法仅表示用户已正确通过人机识别系统验证。您仍需要从后端服务器验证用户的响应令牌。

要了解如何验证用户的响应令牌,请参阅验证用户的响应

处理通信错误

如果您的应用无法成功与 reCAPTCHA 服务通信,则可能是因为 API 遇到了错误。您应该在应用中添加逻辑,以妥善处理这类错误。此外,发生错误时,您的应用应该向用户显示一条消息,向他们解释应用为何无法完成其人机识别系统响应处理。

以下列表显示了最常见 API 错误的状态代码:

RECAPTCHA_INVALID_SITEKEY

网站密钥无效。调用 API 时,检查您是否已成功注册 API 密钥以及是否已以参数形式正确复制该网站密钥。

常量值:12007

RECAPTCHA_INVALID_KEYTYPE

网站密钥类型无效。要创建新的网站密钥,请转到 reCAPTCHA Android 注册网站

常量值:12008

RECAPTCHA_INVALID_PACKAGE_NAME

发起调用的应用的软件包名称与相应网站密钥关联的任何名称都不相符。将发起调用的应用的软件包名称添加到网站密钥(位于 reCAPTCHA 管理控制台)中,或者针对您的网站密钥停用软件包名称验证。

常量值:12013

UNSUPPORTED_SDK_VERSION

设备的 Android SDK 版本不支持此 API。升级到新版 Android SDK,然后尝试再次与该 API 通信。

常量值:12006

TIMEOUT

会话在该 API 等待响应时超时,要么是因为用户未与人机识别系统互动,要么是因为人机识别系统加载进程本身超时。请等待用户再次调用该 API。在此期间,您可以告知用户,他们必须完成人机识别系统验证才能继续使用您的应用。

常量值:15

NETWORK_ERROR

未连接到互联网。确保连接后,请尝试再次与该 API 通信。

常量值:7

ERROR

操作发生一般性故障。

常量值:13

要详细了解 reCAPTCHA API 可返回的状态代码,请参阅 SafetyNetStatusCodes 参考。