בקשת אימות באמצעות SMS באפליקציה ל-Android

כדי לאמת מספרי טלפון באופן אוטומטי, צריך להטמיע גם את החלק של הלקוח וגם את החלק של השרת בתהליך האימות. במאמר הזה מוסבר איך להטמיע את החלק של הלקוח באפליקציה ל-Android.

כדי להתחיל את תהליך האימות של מספר הטלפון באפליקציה ל-Android, שולחים את מספר הטלפון לשרת האימות וקוראים ל-SMS Retriever API כדי להתחיל להאזין להודעת SMS שמכילה קוד חד-פעמי לאפליקציה. אחרי שמקבלים את ההודעה, שולחים את הקוד החד-פעמי בחזרה לשרת כדי להשלים את תהליך האימות.

כדי להכין את האפליקציה, מבצעים את השלבים שמפורטים בקטעים הבאים.

דרישות מוקדמות לאפליקציה

מוודאים שקובץ ה-build של האפליקציה כולל את הערכים הבאים:

  • ‫minSdkVersion מגרסה 19 ומעלה
  • ‫compileSdkVersion בגרסה 28 ומעלה

הגדרת האפליקציה

בקובץ build.gradle ברמת הפרויקט, צריך לכלול את מאגר ה-Maven של Google ואת מאגר מרכזי בקטעים buildscript ו-allprojects:

buildscript {
    repositories {
        google()
        mavenCentral()
    }
}

allprojects {
    repositories {
        google()
        mavenCentral()
    }
}

מוסיפים את התלות ב-Google Play Services בשביל SMS Retriever API אל קובץ ה-build של Gradle של המודול, שבדרך כלל נמצא ב-app/build.gradle:

dependencies {
  implementation 'com.google.android.gms:play-services-auth:22.0.0'
  implementation 'com.google.android.gms:play-services-auth-api-phone:18.3.1'
}

קבלת מספר הטלפון של המשתמש

אתם יכולים לקבל את מספר הטלפון של המשתמש בכל דרך שמתאימה לאפליקציה שלכם. בדרך כלל, חוויית המשתמש הטובה ביותר היא להשתמש בבורר הרמזים כדי לבקש מהמשתמש לבחור מבין מספרי הטלפון ששמורים במכשיר, וכך להימנע מהצורך להקליד ידנית מספר טלפון. כדי להשתמש בבורר הרמזים:

// Construct a request for phone numbers and show the picker
private void requestHint() {
    HintRequest hintRequest = new HintRequest.Builder()
            .setPhoneNumberIdentifierSupported(true)
            .build();

    PendingIntent intent = Auth.CredentialsApi.getHintPickerIntent(
            apiClient, hintRequest);
    startIntentSenderForResult(intent.getIntentSender(),
            RESOLVE_HINT, null, 0, 0, 0);
}

// Obtain the phone number from the result
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
  super.onActivityResult(requestCode, resultCode, data);
  if (requestCode == RESOLVE_HINT) {
      if (resultCode == RESULT_OK) {
          Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
          // credential.getId();  <-- will need to process phone number string
      }
  }
}

הפעלת מאחזר ה-SMS

כשתהיו מוכנים לאמת את מספר הטלפון של המשתמש, קבלו מופע של האובייקט SmsRetrieverClient, קראו ל-startSmsRetriever וצרפו מאזינים להצלחה ולכישלון למשימת אחזור ה-SMS:

// Get an instance of SmsRetrieverClient, used to start listening for a matching
// SMS message.
SmsRetrieverClient client = SmsRetriever.getClient(this /* context */);

// Starts SmsRetriever, which waits for ONE matching SMS message until timeout
// (5 minutes). The matching SMS message will be sent using a Broadcast Intent
// with action SmsRetriever#SMS_RETRIEVED_ACTION.
Task<Void> task = client.startSmsRetriever();

// Listen for success/failure of the start Task. If in a background thread, this
// can be made blocking using Tasks.await(task, [timeout]);
task.addOnSuccessListener(new OnSuccessListener<Void>() {
  @Override
  public void onSuccess(Void aVoid) {
    // Successfully started retriever, expect broadcast intent
    // ...
  }
});

task.addOnFailureListener(new OnFailureListener() {
  @Override
  public void onFailure(@NonNull Exception e) {
    // Failed to start retriever, inspect Exception for more details
    // ...
  }
});

משימת אחזור ה-SMS מאזינה במשך עד חמש דקות להודעת SMS שמכילה מחרוזת ייחודית שמזהה את האפליקציה.

שליחת מספר הטלפון לשרת

אחרי שמקבלים את מספר הטלפון של המשתמש ומתחילים להאזין להודעות SMS, שולחים את מספר הטלפון של המשתמש לשרת האימות בכל שיטה (בדרך כלל באמצעות בקשת HTTPS POST).

השרת שלכם יוצר הודעת אימות ושולח אותה ב-SMS למספר הטלפון שציינתם. איך מבצעים אימות ב-SMS בשרת

קבלת הודעות אימות

כשמתקבלת הודעת אימות במכשיר של המשתמש, Play Services משדרת לאפליקציה שלכם Intent מסוג SmsRetriever.SMS_RETRIEVED_ACTION שמכיל את הטקסט של ההודעה. צריך להשתמש בBroadcastReceiver כדי לקבל את הודעת האימות הזו.

ב-handler של onReceive ב-BroadcastReceiver, מקבלים את הטקסט של הודעת האימות (ואת כתובת השולח, אם רוצים) מהתוספות של Intent:

/**
  *   BroadcastReceiver to wait for SMS messages. This can be registered either
  *   in the AndroidManifest or at runtime. Filters Intents on
  *   SmsRetriever.SMS_RETRIEVED_ACTION.
  */
public class MySMSBroadcastReceiver extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {
    if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
      Bundle extras = intent.getExtras();
      Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);

      switch(status.getStatusCode()) {
        case CommonStatusCodes.SUCCESS:
          // (Optional) Get SMS Sender address - only available in
          // GMS version 24.20 onwards, else it will return null
          String senderAddress = extras.getString(SmsRetriever.EXTRA_SMS_ORIGINATING_ADDRESS);
          // Get SMS message contents
          String message = extras.getString(SmsRetriever.EXTRA_SMS_MESSAGE);
          // Extract one-time code from the message and complete verification
          // by sending the code back to your server.
          break;
        case CommonStatusCodes.TIMEOUT:
          // Waiting for SMS timed out (5 minutes)
          // Handle the error ...
          break;
      }
    }
  }
}

כדי לרשום את BroadcastReceiver, צריך להשתמש באפשרויות הבאות:

  • מסנן Intent: com.google.android.gms.auth.api.phone.SMS_RETRIEVED (הערך של הקבוע SmsRetriever.SMS_RETRIEVED_ACTION)
  • הרשאה: com.google.android.gms.auth.api.phone.permission.SEND (הערך של הקבוע SmsRetriever.SEND_PERMISSION)

אפשר לרשום את המקלט בקובץ AndroidManifest.xml של האפליקציה, כמו בדוגמה הבאה, או באופן דינמי באמצעות Context.registerReceiver.

<receiver android:name=".MySMSBroadcastReceiver" android:exported="true"
          android:permission="com.google.android.gms.auth.api.phone.permission.SEND">
    <intent-filter>
        <action android:name="com.google.android.gms.auth.api.phone.SMS_RETRIEVED"/>
    </intent-filter>
</receiver>

שליחת הקוד החד-פעמי מהודעת האימות לשרת

עכשיו, כשיש לכם את הטקסט של הודעת האימות, אתם יכולים להשתמש בביטוי רגולרי או בלוגיקה אחרת כדי לקבל את הקוד החד-פעמי מההודעה. הפורמט של הקוד החד-פעמי תלוי באופן שבו הטמעתם אותו בשרת.

לבסוף, שולחים את הקוד החד-פעמי לשרת דרך חיבור מאובטח. כשהשרת מקבל את הקוד החד-פעמי, הוא מתעד שמספר הטלפון אומת.