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

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

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

לפני שמתחילים

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

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

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

  • minSdkVersion בגרסה 19 ואילך
  • compileSdkVersion בגרסה 28 ומעלה

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

בקובץ build.gradle ברמת הפרויקט, צריך לכלול את מאגר Maven של Google ואת מאגר Maven המרכזי גם בקטע 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:21.3.0'
  implementation 'com.google.android.gms:play-services-auth-api-phone:18.1.0'
}

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
      }
  }
}

2. הפעלת הכלי לאחזור הודעות 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 via 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 שמכילה מחרוזת ייחודית שמזהה את האפליקציה.

3. שולחים את מספר הטלפון לשרת

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

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

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

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

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

/**
 * BroadcastReceiver to wait for SMS messages. This can be registered either
 * in the AndroidManifest or at runtime.  Should filter 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 עם מסנן הכוונה 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>

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

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

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