android - Android ReCaptcha:未显示复选框
问题描述
我使用Android SafetyNet ReCaptcha在我的 Android 应用程序中显示 Google 验证码。问题是当我测试它时,复选框永远不会显示。相反,验证码显示得很好,它的进度条有点动画,然后它没有任何错误地完成,确认我是一个人。这种行为是正常的,没有任何错误。
但。我想强制验证码,这似乎工作得很好,就像我上面描述的那样,显示复选框。通过“复选框”,我的意思是例如“显示人类用户必须声称通过检查来识别的人行横道的复选框”。官方文档没有解释怎么做:https ://developer.android.com/training/safetynet/recaptcha#send-request
资源(文档和 StackOverflow)
- 文档:1个链接但不相关
我已遵循此文档:https ://developer.android.com/training/safetynet/recaptcha#send-request 。但是,它没有提供有关如何解决我的问题的任何信息。
- StackOverflow:1个问题但不相关
我还没有找到任何相关的问题。事实上,我没有发现任何关于如何为 Android 实现 ReCaptcha 的问题,除了一个非常短的问题(它没有提供任何有用的数据来解决我的问题)。
我的实现
我将向你展示我是如何实现他们的 API ReCaptcha for Android (SafetyNet ReCaptcha) 来帮助你的。
过程
我的应用程序的用户可以注册、登录、退出。
当用户启动我的应用程序时,会出现一个闪屏。如果用户未连接,则邀请他触摸按钮。
2.1。如果他触摸按钮,就会启动 ReCaptcha。
2.1.1. If the ReCaptcha is successfully completed, then the user can sign-up and sign-in with his Google account (I use Google Firebase Auth and even AuthUI). 2.1.2. Otherwise, nothing occurs : he'll have to re-try to complete ReCaptcha.
来源
SplashScreen.java(一个AppCompatActivity
类):监听按钮上的“触摸”事件的“onClick”事件处理程序
在简历中:我将监听器附加到按钮上。因此,如果单击后者,我会调用verifyWithRecaptcha
(synchrone! 并且它是自愿的) Executor
。然后我打电话给谷歌的服务器,以确保验证码是由人类完成的,而不是机器人完成的,这要感谢我的班级NetworkUseRecaptcha
提供了result
谷歌的服务器。
final Context that = this;
button_splash_screen_recaptcha.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final Executor executor = new Executor() {
@Override
public void execute(@NonNull Runnable command) {
command.run();
}
};
executor.execute(new Runnable() {
@Override
public void run() {
SafetyNet.getClient(that).verifyWithRecaptcha("PUBLIC KEY")
.addOnSuccessListener(executor,
new OnSuccessListener<SafetyNetApi.RecaptchaTokenResponse>() {
@Override
public void onSuccess(final SafetyNetApi.RecaptchaTokenResponse response) {
String userResponseToken = response.getTokenResult();
if (!userResponseToken.isEmpty()) {
String[] parameters = new String[2];
parameters[0] = "SECRET KEY";
parameters[1] = userResponseToken;
new NetworkUseRecaptcha(new RecaptchaPostExecuteCallback() {
@Override
public void onTaskCompleted(String result, boolean background_error) {
if(background_error) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(that,"Error N°2: Unable to check the captcha.", Toast.LENGTH_SHORT).show();
}
});
return;
}
try {
final JSONObject json_response = new JSONObject(result);
if(!json_response.isNull("success") && json_response.getBoolean("success")) {
final List<AuthUI.IdpConfig> providers = ImmutableList.of(
new AuthUI.IdpConfig.GoogleBuilder().build()
);
startActivityForResult(
AuthUI.getInstance()
.createSignInIntentBuilder()
.setAvailableProviders(providers)
.setAlwaysShowSignInMethodScreen(true)
.setLogo(R.drawable.yellow_logo)
.setTheme(R.style.LoginTheme)
.build(),
REQUEST_CODE_SIGN_IN
);
} else {
Toast.makeText(that,"Error N°4: Unable to check the captcha.", Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(that,"Error N°3: Unable to check the captcha.", Toast.LENGTH_SHORT).show();
}
});
}
}
}).execute(parameters);
}
}
})
.addOnFailureListener(executor, new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
System.err.println(e);
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(that,"Error N°1: Unable to check the captcha.", Toast.LENGTH_SHORT).show();
}
});
}
});
}
});
}
});
NetworkUseRecaptcha.java:我的类允许我联系 Google 的服务器以验证验证码
class NetworkUseRecaptcha extends AsyncTask<String, Void, String> {
private final RecaptchaPostExecuteCallback post_execute_callback;
private boolean background_error;
NetworkUseRecaptcha(RecaptchaPostExecuteCallback post_execute_callback) {
this.post_execute_callback = post_execute_callback;
background_error = false;
}
@Override
protected String doInBackground(String[] parameters) {
StringBuilder string_builder = new StringBuilder();
try {
URL url = new URL("https://www.google.com/recaptcha/api/siteverify");
HttpsURLConnection https_url_connection = (HttpsURLConnection) url.openConnection();
https_url_connection.setRequestMethod("POST");
https_url_connection.setDoOutput(false);
https_url_connection.setUseCaches(false);
OutputStream os = https_url_connection.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8));
writer.write("secret=" + parameters[0] + "&response=" + parameters[1]);
writer.flush();
writer.close();
os.close();
InputStream input_stream = https_url_connection.getInputStream();
BufferedReader buffered_reader = new BufferedReader(new InputStreamReader(input_stream));
String line;
while((line = buffered_reader.readLine()) != null) {
string_builder.append(line);
}
buffered_reader.close();
} catch (Exception e) {
background_error = true;
}
return string_builder.toString();
}
@Override
protected void onPostExecute(String result) {
post_execute_callback.onTaskCompleted(result, background_error);
}
}
解决方案
https://developers.google.com/android/reference/com/google/android/gms/safetynet/SafetyNetClient#verifyWithRecaptcha(java.lang.String):“如果 reCAPTCHA 确信这是真实设备上的真实用户它将返回一个没有挑战的令牌。否则它将在返回令牌之前提供视觉/音频挑战来证明用户的人性。”
所以我的愿望是不可能具体化的......
推荐阅读
- netlogo - NetLogo - 海龟在特定区域内的定向运动
- c++ - 提升,来自字符串问题的 posix 时间
- angular - 使用 ngFor 添加 mat-slide-toggle 时防止动画
- c# - 如何禁用 ListBox 中的按键导航但继续检测按键事件?
- tableau-api - Tableau elseif 语句
- powerbi - Power BI / Power Query [M 代码] - 添加基于源的自定义列
- docker - Dockerfile - 如何定义主机文件系统到容器的挂载
- jquery - 如果单击一次,如何获得返回 false 的链接,如果再次单击则返回 true?
- rest - 制作 Postman 测试 - Grails
- sonarqube - 如何将带有级联测试套件的 PHPUnit 报告导入 Sonarqube?