یک رمز عبور ایجاد کنید

قبل از اینکه کاربران شما بتوانند با کلیدهای عبور احراز هویت کنند، برنامه شما ابتدا باید کلید عبور را برای حساب آنها ثبت یا ایجاد کند.

برای ایجاد کلید عبور، جزئیات مورد نیاز برای ایجاد کلید عبور را از سرور برنامه خود دریافت کنید و سپس API مدیریت اعتبار را فراخوانی کنید، که یک جفت کلید عمومی و خصوصی را برمی‌گرداند. کلید خصوصی برگردانده شده در یک ارائه دهنده اعتبارنامه، مانند مدیریت رمز عبور گوگل، به عنوان یک کلید عبور ذخیره می‌شود. کلید عمومی در سرور برنامه شما ذخیره می‌شود.

کلیدهای عبور در یک ارائه‌دهنده اعتبارنامه و کلیدهای عمومی در سرور برنامه ذخیره می‌شوند.
شکل ۱: ایجاد کلیدهای عبور

پیش‌نیازها

مطمئن شوید که پیوندهای دارایی دیجیتال (Digital Asset Links) را تنظیم کرده‌اید و دستگاه‌هایی را هدف قرار می‌دهید که اندروید ۹ (سطح API 28) یا بالاتر را اجرا می‌کنند.

نمای کلی

این راهنما بر تغییرات مورد نیاز در برنامه کلاینت طرف متکی شما برای ایجاد کلید عبور تمرکز دارد و خلاصه‌ای از پیاده‌سازی سرور برنامه طرف متکی را ارائه می‌دهد. برای کسب اطلاعات بیشتر در مورد ادغام سمت سرور، به ثبت کلید عبور سمت سرور مراجعه کنید.

  1. افزودن وابستگی‌ها به برنامه : کتابخانه‌های Credential Manager مورد نیاز را اضافه کنید.
  2. نمونه‌سازی مدیر اعتبارنامه : یک نمونه از مدیر اعتبارنامه ایجاد کنید.
  3. دریافت گزینه‌های ایجاد اعتبارنامه از سرور برنامه : از سرور برنامه خود، جزئیات مورد نیاز برای ایجاد کلید عبور، مانند اطلاعات مربوط به برنامه، کاربر، و همچنین یک challenge و سایر فیلدها را به برنامه کلاینت ارسال کنید.
  4. درخواست رمز عبور : در برنامه خود، از جزئیات دریافتی از سرور برنامه برای ایجاد یک شیء GetPublicKeyCredentialOption استفاده کنید و از این شیء برای فراخوانی متد credentialManager.getCredential() برای ایجاد یک رمز عبور استفاده کنید.
  5. مدیریت پاسخ ایجاد کلید عبور : وقتی اعتبارنامه‌ها را در برنامه کلاینت خود دریافت می‌کنید، باید کلید عمومی را رمزگذاری، سریالایز و سپس به سرور برنامه ارسال کنید. همچنین باید هر یک از استثنائاتی را که ممکن است در صورت ایجاد کلید عبور رخ دهد، مدیریت کنید.
  6. تأیید و ذخیره کلید عمومی در سرور : مراحل سمت سرور را برای تأیید منشأ اعتبارنامه تکمیل کنید و سپس کلید عمومی را ذخیره کنید.
  7. به کاربر اطلاع دهید : به کاربر اطلاع دهید که رمز عبور او ایجاد شده است.

۱. وابستگی‌ها را به برنامه خود اضافه کنید

وابستگی‌های زیر را به فایل build.gradle ماژول برنامه خود اضافه کنید:

کاتلین

dependencies {
    implementation("androidx.credentials:credentials:1.6.0-beta03")
    implementation("androidx.credentials:credentials-play-services-auth:1.6.0-beta03")
}

شیار

dependencies {
    implementation "androidx.credentials:credentials:1.6.0-beta03"
    implementation "androidx.credentials:credentials-play-services-auth:1.6.0-beta03"
}

۲. نمونه‌سازی مدیر اعتبارنامه

از زمینه برنامه یا فعالیت خود برای ایجاد یک شیء CredentialManager استفاده کنید.

// Use your app or activity context to instantiate a client instance of
// CredentialManager.
private val credentialManager = CredentialManager.create(context)

۳. گزینه‌های ایجاد اعتبارنامه را از سرور برنامه خود دریافت کنید

وقتی کاربر روی دکمه‌ی «ایجاد رمز عبور» کلیک می‌کند یا وقتی کاربر جدیدی ثبت‌نام می‌کند، از برنامه‌ی خود درخواستی به سرور برنامه ارسال کنید تا اطلاعات لازم برای شروع فرآیند ثبت رمز عبور را دریافت کند.

از یک کتابخانه سازگار با FIDO در سرور برنامه خود استفاده کنید تا اطلاعات مورد نیاز برای ایجاد یک کلید عبور، مانند اطلاعات مربوط به کاربر، برنامه و ویژگی‌های پیکربندی اضافی، را برای برنامه کلاینت خود ارسال کنید. برای کسب اطلاعات بیشتر، به ثبت کلید عبور سمت سرور مراجعه کنید.

در برنامه کلاینت، گزینه‌های ایجاد کلید عمومی ارسال شده توسط سرور برنامه را رمزگشایی کنید. این گزینه‌ها معمولاً در قالب JSON نمایش داده می‌شوند. برای کسب اطلاعات بیشتر در مورد نحوه انجام این رمزگشایی برای کلاینت‌های وب، به بخش رمزگذاری و رمزگشایی مراجعه کنید. برای برنامه‌های کلاینت اندروید، باید رمزگشایی را جداگانه انجام دهید.

قطعه کد زیر ساختار گزینه‌های ایجاد کلید عمومی ارسال شده توسط سرور برنامه را نشان می‌دهد:

{
  "challenge": "<base64url-encoded challenge>",
  "rp": {
    "name": "<relying party name>",
    "id": "<relying party host name>"
  },
  "user": {
    "id": "<base64url-encoded user ID>",
    "name": "<user name>",
    "displayName": "<user display name>"
  },
  "pubKeyCredParams": [
    {
      "type": "public-key",
      "alg": -7
    }
  ],
  "attestation": "none",
  "excludeCredentials": [
    {
        "id": "<base64url-encoded credential ID to exclude>", 
        "type": "public-key"
    }
  ],
  "authenticatorSelection": {
    "requireResidentKey": true,
    "residentKey": "required",
    "userVerification": "required"
  }
}

فیلدهای کلیدی در گزینه‌های ایجاد کلید عمومی عبارتند از:

  • challenge : یک رشته تصادفی تولید شده توسط سرور که برای جلوگیری از حملات بازپخش استفاده می‌شود.
  • rp : جزئیات مربوط به برنامه.
    • rp.name : نام برنامه.
    • rp.id : دامنه یا زیر دامنه برنامه.
  • user : جزئیات مربوط به کاربر.
    • id : شناسه منحصر به فرد کاربر. این مقدار نباید شامل اطلاعات شناسایی شخصی، مانند آدرس‌های ایمیل یا نام‌های کاربری باشد. می‌توانید از یک مقدار تصادفی ۱۶ بایتی استفاده کنید.
    • name : یک شناسه منحصر به فرد برای حساب کاربری که کاربر آن را تشخیص می‌دهد، مانند آدرس ایمیل یا نام کاربری. این شناسه در انتخابگر حساب کاربری نمایش داده می‌شود. در صورت استفاده از نام کاربری، از همان مقداری که در احراز هویت با رمز عبور استفاده شده است، استفاده کنید.
    • displayName : یک نام اختیاری و کاربرپسند برای حسابی که قرار است در انتخابگر حساب نمایش داده شود.
  • authenticatorSelection : جزئیات مربوط به دستگاهی که برای احراز هویت استفاده خواهد شد.

    • authenticatorAttachment : نشان دهنده‌ی احراز هویت ترجیحی است. مقادیر ممکن به شرح زیر است: - platform : این مقدار برای یک احراز هویت تعبیه شده در دستگاه کاربر، مانند حسگر اثر انگشت، استفاده می‌شود. - cross-platform : این مقدار برای دستگاه‌های رومینگ مانند کلیدهای امنیتی استفاده می‌شود. معمولاً در زمینه‌ی کلید عبور استفاده نمی‌شود. - نامشخص (توصیه می‌شود): نامشخص گذاشتن این مقدار به کاربران این امکان را می‌دهد که کلیدهای عبور را در دستگاه‌های مورد نظر خود ایجاد کنند. در بیشتر موارد، نامشخص گذاشتن پارامتر بهترین گزینه است.
      • requireResidentKey : برای ایجاد یک کلید عبور، مقدار این فیلد Boolean را برابر با true قرار دهید.
      • residentKey : برای ایجاد یک کلید عبور، مقدار را روی required تنظیم کنید.
      • userVerification : برای تعیین الزامات تأیید کاربر در طول ثبت رمز عبور استفاده می‌شود. مقادیر ممکن به شرح زیر است: - preferred : اگر تجربه کاربری را بر حفاظت اولویت می‌دهید، از این مقدار استفاده کنید، مانند محیط‌هایی که تأیید کاربر باعث ایجاد اصطکاک بیشتری نسبت به حفاظت می‌شود. - required : اگر فراخوانی یک روش تأیید کاربر موجود در دستگاه الزامی است، از این مقدار استفاده کنید. - discouraged : اگر استفاده از یک روش تأیید کاربر نامطلوب است، از این مقدار استفاده کنید.
        برای کسب اطلاعات بیشتر در مورد userVerification ، به بخش بررسی عمیق userVerification مراجعه کنید.
  • excludeCredentials : شناسه‌های اعتبارنامه را در یک آرایه فهرست می‌کند تا در صورت وجود رمز عبور تکراری با همان ارائه‌دهنده اعتبارنامه، از ایجاد آن جلوگیری شود.

۴. درخواست رمز عبور

پس از اینکه گزینه‌های ایجاد کلید عمومی سمت سرور را تجزیه کردید، با قرار دادن این گزینه‌ها در یک شیء CreatePublicKeyCredentialRequest و فراخوانی createCredential() یک کلید عبور ایجاد کنید.

درخواست createPublicKeyCredentialRequest شامل موارد زیر است:

  • requestJson : گزینه‌های ایجاد اعتبارنامه که توسط سرور برنامه ارسال می‌شود.
  • preferImmediatelyAvailableCredentials : این یک فیلد بولی اختیاری است که تعریف می‌کند آیا فقط از اعتبارنامه‌های موجود در محل یا اعتبارنامه‌های همگام‌سازی‌شده توسط ارائه‌دهنده اعتبارنامه برای انجام درخواست استفاده شود، به جای اعتبارنامه‌های کلیدهای امنیتی یا جریان‌های کلید ترکیبی . کاربردهای احتمالی به شرح زیر است:
    • false (پیش‌فرض): اگر فراخوانی Credential Manager توسط یک اقدام صریح کاربر انجام شده باشد، از این مقدار استفاده کنید.
    • true : اگر Credential Manager به صورت فرصت‌طلبانه فراخوانی شود، مانند اولین باری که برنامه را باز می‌کنید، از این مقدار استفاده کنید.
      اگر مقدار را روی true تنظیم کنید و هیچ اعتبارنامه‌ای فوراً در دسترس نباشد، Credential Manager هیچ رابط کاربری (UI) را نشان نمی‌دهد و درخواست بلافاصله با شکست مواجه می‌شود و برای درخواست‌های get خطای NoCredentialException و برای درخواست‌های create CreateCredentialNoCreateOptionException را برمی‌گرداند.
  • origin : این فیلد به طور خودکار برای برنامه‌های اندروید تنظیم می‌شود. برای مرورگرها و برنامه‌های مشابه با دسترسی ویژه که نیاز به تنظیم origin دارند، به بخش «ایجاد تماس‌های مدیریت اعتبار از طرف سایر طرفین برای برنامه‌های با دسترسی ویژه» مراجعه کنید.
  • isConditional : این یک فیلد اختیاری است که به طور پیش‌فرض روی false تنظیم شده است. وقتی این مقدار را روی true تنظیم می‌کنید و اگر کاربری رمز عبور نداشته باشد، دفعه بعد که با رمز عبور ذخیره شده وارد سیستم شود، شما به طور خودکار از طرف او یک رمز عبور ایجاد می‌کنید. رمز عبور در ارائه دهنده اعتبارنامه کاربر ذخیره می‌شود. ویژگی ایجاد شرطی به آخرین نسخه androidx.credentials نیاز دارد.

فراخوانی تابع createCredential() رابط کاربری برگه پایانی داخلی Credential Manager را اجرا می‌کند که کاربر را وادار به استفاده از کلید عبور و انتخاب یک ارائه‌دهنده اعتبارنامه و حساب برای ذخیره‌سازی می‌کند. با این حال، اگر isConditional روی true تنظیم شده باشد، رابط کاربری برگه پایانی نمایش داده نمی‌شود و کلید عبور به طور خودکار ایجاد می‌شود.

۵. پاسخ را مدیریت کنید

پس از تأیید کاربر با استفاده از قفل صفحه نمایش دستگاه، یک کلید عبور ایجاد شده و در ارائه دهنده اعتبارنامه انتخابی کاربر ذخیره می‌شود.

پاسخی که پس از فراخوانی موفقیت‌آمیز createCredential() دریافت می‌کنید، یک شیء PublicKeyCredential است.

اعتبارنامه PublicKeyCredential به شکل زیر است:

{
  "id": "<identifier>",
  "type": "public-key",
  "rawId": "<identifier>",
  "response": {
    "clientDataJSON": "<ArrayBuffer encoded object with the origin and signed challenge>",
    "attestationObject": "<ArrayBuffer encoded object with the public key and other information.>"
  },
  "authenticatorAttachment": "platform"
}

در برنامه‌ی کلاینت، شیء را سریالایز کنید و آن را به سرور برنامه ارسال کنید.

کدی را برای مدیریت خطاها اضافه کنید، همانطور که در قطعه کد زیر نشان داده شده است:

fun handleFailure(e: CreateCredentialException) {
    when (e) {
        is CreatePublicKeyCredentialDomException -> {
            // Handle the passkey DOM errors thrown according to the
            // WebAuthn spec.
        }
        is CreateCredentialCancellationException -> {
            // The user intentionally canceled the operation and chose not
            // to register the credential.
        }
        is CreateCredentialInterruptedException -> {
            // Retry-able error. Consider retrying the call.
        }
        is CreateCredentialProviderConfigurationException -> {
            // Your app is missing the provider configuration dependency.
            // Most likely, you're missing the
            // "credentials-play-services-auth" module.
        }
        is CreateCredentialCustomException -> {
            // You have encountered an error from a 3rd-party SDK. If you
            // make the API call with a request object that's a subclass of
            // CreateCustomCredentialRequest using a 3rd-party SDK, then you
            // should check for any custom exception type constants within
            // that SDK to match with e.type. Otherwise, drop or log the
            // exception.
        }
        else -> Log.w(TAG, "Unexpected exception type ${e::class.java.name}")
    }
}

۶. کلید عمومی را در سرور برنامه تأیید و ذخیره کنید

در سرور برنامه، باید اعتبار کلید عمومی را تأیید کنید و سپس کلید عمومی را ذخیره کنید .

برای تأیید منشأ اعتبارنامه کلید عمومی، آن را با فهرست مجاز برنامه‌های تأیید شده مقایسه کنید. اگر منشأ یک کلید ناشناخته است، آن را رد کنید.

برای به دست آوردن اثر انگشت SHA 256 برنامه:

  1. با اجرای دستور زیر در ترمینال، گواهی امضای برنامه‌ی انتشار خود را چاپ کنید:

    keytool -list -keystore <path-to-apk-signing-keystore>
    

    در پاسخ، اثر انگشت SHA 256 گواهی امضا را که به عنوان Certificate fingerprints block : SHA256 ذکر شده است، شناسایی کنید.

  2. اثر انگشت SHA256 را با کدگذاری base64url رمزگذاری کنید. این مثال پایتون نحوه رمزگذاری صحیح اثر انگشت را نشان می‌دهد:

    import binascii
    import base64
    fingerprint = '<SHA256 finerprint>' # your app's SHA256 fingerprint
    print(base64.urlsafe_b64encode(binascii.a2b_hex(fingerprint.replace(':', ''))).decode('utf8').replace('=', ''))
    
  3. عبارت android:apk-key-hash : را به ابتدای خروجی مرحله قبل اضافه کنید تا چیزی شبیه به خروجی زیر به دست آید:

    android:apk-key-hash:<encoded SHA 256 fingerprint>
    

    نتیجه باید با یک مبدأ مجاز در سرور برنامه شما مطابقت داشته باشد. اگر چندین گواهی امضا دارید، مانند گواهی‌های اشکال‌زدایی و انتشار، یا چندین برنامه، فرآیند را تکرار کنید و همه مبدأها را در سرور برنامه معتبر بپذیرید.

۷. به کاربر اطلاع دهید

پس از ایجاد موفقیت‌آمیز کلید عبور، به کاربران خود در مورد کلید عبور اطلاع دهید و به آنها اطلاع دهید که می‌توانند کلیدهای عبور خود را از برنامه ارائه دهنده اعتبارنامه یا از داخل تنظیمات برنامه مدیریت کنند. با استفاده از یک کادر محاوره‌ای سفارشی، اعلان یا نوار میان وعده به کاربران اطلاع دهید. از آنجایی که ایجاد کلید عبور غیرمنتظره توسط یک نهاد مخرب نیاز به یک هشدار امنیتی فوری دارد، مکمل این روش‌های درون برنامه‌ای با ارتباطات خارجی، مانند ایمیل، را در نظر بگیرید.

تجربه کاربری را افزایش دهید

برای بهبود تجربه کاربری هنگام پیاده‌سازی ثبت‌نام با Credential Manager، افزودن قابلیت‌هایی برای بازیابی اعتبارنامه‌ها و غیرفعال کردن دیالوگ‌های تکمیل خودکار را در نظر بگیرید.

افزودن قابلیت بازیابی اعتبارنامه‌ها در دستگاه جدید

برای اینکه کاربران بتوانند به راحتی در دستگاه جدید به حساب‌های خود وارد شوند، قابلیت بازیابی اعتبارنامه‌ها (Restore Credentials) را پیاده‌سازی کنید. افزودن اعتبارنامه‌های بازیابی با BackupAgent ، کاربران را هنگام باز کردن برنامه بازیابی شده شما در دستگاه جدید، وارد سیستم می‌کند و به آنها اجازه می‌دهد بلافاصله از برنامه شما استفاده کنند.

غیرفعال کردن تکمیل خودکار فیلدهای اطلاعات کاربری (اختیاری)

برای صفحات برنامه که انتظار می‌رود کاربران از رابط کاربری برگه پایینی Credential Manager برای احراز هویت استفاده کنند، ویژگی isCredential را به فیلدهای نام کاربری و رمز عبور اضافه کنید. این کار از همپوشانی دیالوگ‌های تکمیل خودکار ( FillDialog و SaveDialog ) با رابط کاربری برگه پایینی Credential Manager جلوگیری می‌کند.

ویژگی isCredential در اندروید ۱۴ و بالاتر پشتیبانی می‌شود.

مثال زیر نشان می‌دهد که چگونه می‌توانید ویژگی isCredential را به فیلدهای نام کاربری و رمز عبور مربوطه در نماهای مربوطه برای برنامه خود اضافه کنید:

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:isCredential="true" />

مراحل بعدی