نسخه ۲۰۲۵، فصل چهارم: یاد بگیرید چگونه با استفاده از رابط برنامه‌نویسی مدیریت اعتبار در برنامه اندروید خود، مراحل احراز هویت را ساده کنید

۱. قبل از شروع

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

رمزهای عبور به طور گسترده استفاده می‌شوند اما...

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

اندروید برای ساده‌سازی تجربه ورود به سیستم و رفع خطرات امنیتی با پشتیبانی از کلیدهای عبور ، استاندارد صنعتی نسل بعدی برای احراز هویت بدون رمز عبور ، روی ایجاد رابط برنامه‌نویسی مدیریت اعتبارنامه (Credential Manager API) کار کرده است.

مدیریت اعتبارنامه (Credential Manager) پشتیبانی از کلیدهای عبور را گرد هم می‌آورد و آن را با روش‌های سنتی احراز هویت مانند رمزهای عبور، ورود با گوگل و غیره ترکیب می‌کند.

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

در این آزمایشگاه کد، شما یاد خواهید گرفت که چگونه با استفاده از کلیدهای عبور و رمز عبور با استفاده از API مدیریت اعتبارنامه (Credential Manager API) ثبت نام کنید و از آنها برای اهداف احراز هویت در آینده استفاده کنید. 2 جریان وجود دارد از جمله:

  • ثبت نام: با استفاده از رمز عبور و رمز عبور.
  • ورود: با استفاده از کلیدهای عبور و رمز عبور ذخیره شده.

پیش‌نیازها

  • آشنایی اولیه با نحوه اجرای برنامه‌ها در اندروید استودیو
  • آشنایی اولیه با جریان احراز هویت در برنامه‌های اندروید
  • درک اولیه از کلیدهای عبور

آنچه یاد خواهید گرفت

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

آنچه نیاز دارید

یکی از ترکیب‌های دستگاه زیر:

  • یک دستگاه اندروید که اندروید ۹ یا بالاتر (برای رمز عبور) و اندروید ۴.۴ یا بالاتر (برای احراز هویت رمز عبور از طریق API مدیریت اعتبار) را اجرا می‌کند.
  • دستگاه ترجیحاً دارای حسگر بیومتریک.
  • حتماً قفل صفحه (بیومتریک یا غیره) را ثبت کنید.
  • نسخه افزونه کاتلین: ۱.۸.۱۰

۲. آماده شوید

این برنامه نمونه برای اعتبارسنجی مدیر اعتبار و ادامه کار، به یک دارایی دیجیتال که به یک وب‌سایت لینک شده است نیاز دارد، بنابراین شناسه rp مورد استفاده در پاسخ‌های ساختگی از یک سرور 3P ساختگی است. اگر می‌خواهید پاسخ ساختگی خودتان را امتحان کنید، دامنه برنامه خود را اضافه کنید و فراموش نکنید که پیوند دارایی دیجیتال را همانطور که در اینجا ذکر شد، تکمیل کنید.

از همان debug.keystore ذکر شده در پروژه برای ساخت نسخه‌های اشکال‌زدایی و انتشار استفاده کنید تا پیوند دارایی دیجیتال نام بسته و sha را در سرور آزمایشی خود تأیید کنید. (این کار قبلاً برای برنامه نمونه در build.gradle برای شما انجام شده است).

  1. این مخزن را از شاخه‌ی credman_codelab روی لپ‌تاپ خود کلون کنید: https://github.com/android/identity-samples/tree/credman_codelab
git clone -b credman_codelab https://github.com/android/identity-samples.git
  1. به ماژول CredentialManager بروید و پروژه را در اندروید استودیو باز کنید.

بیایید وضعیت اولیه برنامه را ببینیم

برای مشاهده‌ی وضعیت اولیه‌ی برنامه، مراحل زیر را دنبال کنید:

  1. برنامه را اجرا کنید.
  2. شما یک صفحه اصلی با دکمه‌های ثبت نام و ورود می‌بینید. این دکمه‌ها هنوز کاری انجام نمی‌دهند، اما در بخش‌های بعدی قابلیت آنها را فعال خواهیم کرد.

7a6fe80f4cf877a8.jpeg

۳. امکان ثبت نام با استفاده از رمز عبور را اضافه کنید

هنگام ثبت نام برای یک حساب کاربری جدید در یک برنامه اندروید که از رابط برنامه‌نویسی کاربردی مدیریت اعتبارنامه (Credential Manager API) استفاده می‌کند، کاربران می‌توانند برای حساب خود یک کلید عبور ایجاد کنند. این کلید عبور به طور ایمن در ارائه دهنده اعتبارنامه انتخابی کاربر ذخیره می‌شود و برای ورودهای بعدی، بدون نیاز به وارد کردن رمز عبور توسط کاربر در هر بار، مورد استفاده قرار می‌گیرد.

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

ثبت نام با رمز عبور

کد داخل CredentialManager/app/src/main/java/com/google/credentialmanager/sample/SignUpScreen.kt یک فیلد متنی با عنوان "username" و یک دکمه برای ثبت نام با رمز عبور تعریف می‌کند.

۱f4c50daa2551f1.jpeg

تعریف لامبدا createCredential() برای استفاده در View Models

اشیاء مدیریت اعتبارنامه (Credential manager) برای ارسال به یک Activity نیاز دارند که با یک Screen مرتبط است. با این حال، عملیات مدیریت اعتبارنامه معمولاً در View Models آغاز می‌شوند و توصیه نمی‌شود که Activityها را در View Models ارجاع دهیم. بنابراین، توابع مدیریت اعتبارنامه را در یک فایل جداگانه به CredentialManagerUtil.kt تعریف می‌کنیم و آنها را در Screens های مناسب ارجاع می‌دهیم، که سپس آنها را به عنوان callback از طریق توابع lambda به View Model های خود منتقل می‌کنند.

کامنت TODO را در تابع createCredential() در فایل CredentialManagerUtil.kt پیدا کنید و تابع CredentialManager.create() را فراخوانی کنید:

CredentialManagerUtil.kt

suspend fun createCredential(
    activity: Activity,
    request: CreateCredentialRequest
): CreateCredentialResponse {
    TODO("Create a CredentialManager object and call createCredential() with a CreateCredentialRequest")
    val credentialManager = CredentialManager.create(activity)
    return credentialManager.createCredential(activity, request)
}

چالش و سایر پاسخ‌های json را به فراخوانی createPasskey() ارسال کنید.

قبل از ایجاد کلید عبور، باید اطلاعات لازم را از سرور درخواست کنید تا در طول فراخوانی createCredential () به API مدیریت اعتبار منتقل شود.

شما از قبل یک پاسخ آزمایشی (mock response) در فایل‌های پروژه خود به نام RegFromServer.txt دارید که پارامترهای لازم را در این codelab برمی‌گرداند.

  • در برنامه خود، به فایل SignUpViewModel.kt بروید، متد signUpWithPasskeys را پیدا کنید که در آن منطق ایجاد کلید عبور و اجازه ورود به کاربر را خواهید نوشت. می‌توانید این متد را در همان کلاس پیدا کنید.
  • بلوک توضیحات TODO را پیدا کنید تا create a CreatePublicKeyCredentialRequest() و کد زیر را جایگزین آن کنید:

ثبت نامViewModel.kt

TODO("Create a CreatePublicKeyCredentialRequest() with necessary registration json from server")
    val request = CreatePublicKeyCredentialRequest(
        jsonProvider.fetchRegistrationJson()
            .replace("<userId>", getEncodedUserId())
            .replace("<userName>", _username.value)
            .replace("<userDisplayName>", _username.value)
            .replace("<challenge>", getEncodedChallenge())
    )

متد jsonProvider.fetchRegistrationJsonFromServer() یک پاسخ JSON از نوع PublicKeyCredentialCreationOptions را از منابع (assets) می‌خواند و JSON ثبت‌شده‌ای را که باید هنگام ایجاد کلید عبور ارسال شود، برمی‌گرداند. ما برخی از مقادیر placeholder را با ورودی‌های کاربر از برنامه خود و برخی از فیلدهای شبیه‌سازی‌شده جایگزین می‌کنیم:

  • این JSON ناقص است و ۴ فیلد دارد که باید جایگزین شوند.
  • شناسه کاربری (UserId) باید منحصر به فرد باشد تا کاربر بتواند چندین رمز عبور (passkey) ایجاد کند (در صورت لزوم). <userId> را با مقدار userId تولید شده جایگزین کنید.
  • <challenge> همچنین باید منحصر به فرد باشد، بنابراین شما یک چالش تصادفی منحصر به فرد ایجاد خواهید کرد. این متد از قبل در کد شما وجود دارد.

یک پاسخ واقعی از سرور PublicKeyCredentialCreationOptions ممکن است گزینه‌های بیشتری را برگرداند. نمونه‌ای از برخی از این فیلدها در زیر آورده شده است:

{
  "challenge": String,
  "rp": {
    "name": String,
    "id": String
  },
  "user": {
    "id": String,
    "name": String,
    "displayName": String
  },
  "pubKeyCredParams": [
    {
      "type": "public-key",
      "alg": -7
    },
    {
      "type": "public-key",
      "alg": -257
    }
  ],
  "timeout": 1800000,
  "attestation": "none",
  "excludeCredentials": [],
  "authenticatorSelection": {
    "authenticatorAttachment": "platform",
    "requireResidentKey": true,
    "residentKey": "required",
    "userVerification": "required"
  }
}

جدول زیر برخی از پارامترهای مهم در شیء PublicKeyCredentialCreationOptions را توضیح می‌دهد:

پارامترها

توضیحات

challenge

یک رشته تصادفی تولید شده توسط سرور که حاوی آنتروپی کافی برای غیرممکن کردن حدس زدن آن است. حداقل باید ۱۶ بایت طول داشته باشد. این مورد الزامی است اما در طول ثبت نام استفاده نمی‌شود، مگر اینکه گواهی انجام شود.

user.id

شناسه منحصر به فرد کاربر. این مقدار نباید شامل اطلاعات شناسایی شخصی، مانند آدرس‌های ایمیل یا نام‌های کاربری باشد. یک مقدار تصادفی ۱۶ بایتی که برای هر حساب ایجاد می‌شود، به خوبی کار خواهد کرد.

user.name

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

user.displayName

این فیلد یک نام اختیاری و کاربرپسندتر برای حساب کاربری است.

rp.id

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

  • name (الزامی): نام برنامه شما
  • ID (اختیاری): مربوط به دامنه یا زیر دامنه است. در صورت عدم وجود، از دامنه فعلی استفاده می‌شود.
  • icon (اختیاری).

pubKeyCredParams

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

excludeCredentials

کاربری که سعی در ثبت یک دستگاه دارد، ممکن است دستگاه‌های دیگری را نیز ثبت کرده باشد. برای محدود کردن ایجاد چندین اعتبارنامه برای یک حساب کاربری در یک احراز هویت واحد، می‌توانید این دستگاه‌ها را نادیده بگیرید. عضو transports ، در صورت وجود، باید حاوی نتیجه فراخوانی getTransports() در طول ثبت هر اعتبارنامه باشد.

authenticatorSelection.authenticatorAttachment

نشان می‌دهد که آیا دستگاه باید به پلتفرم متصل شود یا خیر، یا اینکه نیازی به انجام این کار نیست. این مقدار را روی platform تنظیم کنید. این نشان می‌دهد که شما یک احراز هویت‌کننده می‌خواهید که در دستگاه پلتفرم تعبیه شده باشد و از کاربر خواسته نشود که مثلاً یک کلید امنیتی USB را وارد کند.

residentKey

مقدار required برای ایجاد کلید عبور را مشخص کنید.

ایجاد اعتبارنامه

  1. پس از ایجاد یک CreatePublicKeyCredentialRequest() ، باید فراخوانی createCredential() را با درخواست ایجاد شده فراخوانی کنید.

ثبت نامViewModel.kt

try {
   TODO("Call createCredential() with createPublicKeyCredentialRequest")
   createCredential(request)
   TODO("Complete the registration process after sending public key credential to your server and let the user in")

} catch (e: CreateCredentialException) {
   handlePasskeyFailure(e)
}

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

1ea8ace66135de1e.png

  1. در نهایت، باید فرآیند ثبت‌نام را تکمیل کنید. برنامه یک اعتبارنامه کلید عمومی را به سرور ارسال می‌کند که آن را برای کاربر فعلی ثبت می‌کند.

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

درون متد signUpWithPasskeys() ، کامنت مربوطه را پیدا کرده و با کد زیر جایگزین کنید:

ثبت نامViewModel.kt

try {
    createCredential(request)
    TODO("Complete the registration process after sending public key credential to your server and let the user in")
registerResponse()
    DataProvider.setSignedInThroughPasskeys(true)
    _navigationEvent.emit(NavigationEvent.NavigateToHome(signedInWithPasskeys = true))
} catch (e: CreateCredentialException) {
   handlePasskeyFailure(e)
}
  • registerResponse() true را برمی‌گرداند که نشان می‌دهد سرور ساختگی، کلید عمومی را برای استفاده‌های بعدی ذخیره کرده است.
  • پرچم setSignedInThroughPasskeys را روی true تنظیم کنید.
  • پس از ورود، کاربر را به صفحه اصلی هدایت می‌کنید.

یک PublicKeyCredential واقعی ممکن است شامل فیلدهای بیشتری باشد. نمونه‌ای از این فیلدها در زیر نشان داده شده است:

{
  "id": String,
  "rawId": String,
  "type": "public-key",
  "response": {
    "clientDataJSON": String,
    "attestationObject": String,
  }
}

جدول زیر برخی از پارامترهای مهم در یک شیء PublicKeyCredential را توضیح می‌دهد:

پارامترها

توضیحات

id

یک شناسه رمزگذاری شده Base64URL از کلید عبور ایجاد شده. این شناسه به مرورگر کمک می‌کند تا هنگام احراز هویت، تشخیص دهد که آیا کلید عبور منطبق در دستگاه وجود دارد یا خیر. این مقدار باید در پایگاه داده در backend ذخیره شود.

rawId

یک نسخه شیء ArrayBuffer از شناسه اعتبارنامه.

response.clientDataJSON

یک شیء ArrayBuffer داده‌های کلاینت را کدگذاری کرده است.

response.attestationObject

یک شیء گواهی رمزگذاری شده ArrayBuffer . این شیء حاوی اطلاعات مهمی مانند شناسه RP، پرچم‌ها و کلید عمومی است.

برنامه را اجرا کنید، و می‌توانید روی دکمه‌ی «ثبت نام با رمزهای عبور» کلیک کنید و یک رمز عبور ایجاد کنید.

۴. ذخیره رمز عبور در Credential Provider

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

برای ذخیره رمز عبور کاربر با استفاده از ارائه دهنده رمز عبور، یک CreatePasswordRequest پیاده‌سازی خواهید کرد تا به createCredential() ارسال شود و رمز عبور ذخیره شود.

  • متد signUpWithPassword() را پیدا کنید، TODO را با فراخوانی createPassword جایگزین کنید:

ثبت نامViewModel.kt

TODO("CreatePasswordRequest with entered username and password")
    val passwordRequest = CreatePasswordRequest(_username.value, _password.value)

  • در مرحله بعد، یک اعتبارنامه با درخواست ایجاد رمز عبور ایجاد کنید و اعتبارنامه رمز عبور کاربر را با ارائه دهنده رمز عبور او ذخیره کنید. سپس، کاربر را وارد سیستم کنید. ما استثنائاتی را که در این جریان رخ می‌دهند، به صورت عمومی‌تر دریافت می‌کنیم. TODO را با کد زیر جایگزین کنید:

ثبت نامViewModel.kt

TODO("Create credential with created password request and log the user in")
    try {
        createCredential(passwordRequest)
        simulateServerDelayAndLogIn()
    } catch (e: Exception) {
        val errorMessage = "Exception Message : " + e.message
        Log.e("Auth", errorMessage)
        _passwordCreationError.value = errorMessage
        _isLoading.value = false
    }

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

۵. قابلیت احراز هویت با رمز عبور یا کلید عبور را اضافه کنید

اکنون آماده‌اید تا از آن به عنوان راهی برای احراز هویت ایمن در برنامه خود استفاده کنید.

76e81460b26f9798.png

تعریف لامبدا getCredential() برای استفاده در View Models

مانند قبل، ما getCredential() مربوط به Credential manager را در یک فایل جداگانه به CredentialManagerUtil.kt فراخوانی می‌کنیم تا در Screenهای مناسب به آن ارجاع داده شود و از طریق توابع لامبدا به صورت callback به ViewModelهای آنها ارسال شود.

کامنت TODO را در تابع getCredential() در فایل CredentialManagerUtil.kt پیدا کنید و تابع CredentialManager.get() را فراخوانی کنید:

suspend fun getCredential(
    activity: Activity,
    request: GetCredentialRequest
): GetCredentialResponse {
    TODO("Create a CredentialManager object and call getCredential() with a GetCredentialRequest")
    val credentialManager = CredentialManager.create(activity)
    return credentialManager.getCredential(activity, request)
}

چالش و سایر گزینه‌هایی که باید به متد getPasskey() ارسال شوند را دریافت کنید.

قبل از اینکه از کاربر بخواهید احراز هویت کند، باید پارامترهایی را برای ارسال در WebAuthn JSON از سرور درخواست کنید، از جمله یک چالش.

شما در حال حاضر یک پاسخ ساختگی در فایل‌های خود ( AuthFromServer.txt ) دارید که چنین پارامترهایی را در این آزمایشگاه کد برمی‌گرداند.

  • در برنامه خود، به فایل SignInViewModel.kt بروید، متد signInWithSavedCredentials را پیدا کنید که در آن منطق احراز هویت از طریق کلید عبور یا رمز عبور ذخیره شده را خواهید نوشت و به کاربر اجازه ورود می‌دهید:
  • یک GetPublicKeyCredentialOption() با پارامترهای لازم برای دریافت اعتبارنامه‌ها از ارائه‌دهنده اعتبارنامه خود ایجاد کنید.

ورود به سیستم

TODO("Create a GetPublicKeyCredentialOption() with necessary authentication json from server")
    val getPublicKeyCredentialOption =
        GetPublicKeyCredentialOption(jsonProvider.fetchAuthJson(), null)

متد fetchAuthJsonFromServer() پاسخ JSON احراز هویت را از assets می‌خواند و JSON احراز هویت را برمی‌گرداند تا تمام کلیدهای عبور مرتبط با این حساب کاربری را بازیابی کند.

پارامتر دوم GetPublicKeyCredentialOption() clientDataHash است - هشی که برای تأیید هویت طرف متکی استفاده می‌شود. این را فقط در صورتی تنظیم کنید که GetCredentialRequest.origin را تنظیم کرده باشید. برای برنامه نمونه، این مقدار روی null تنظیم شده است.

توجه: سرور این codelab به گونه‌ای طراحی شده است که یک JSON را برگرداند که تا حد امکان شبیه به دیکشنری PublicKeyCredentialRequestOptions باشد که به فراخوانی getCredential() از API ارسال می‌شود. قطعه کد زیر شامل چند نمونه از گزینه‌هایی است که می‌توانید در یک پاسخ واقعی دریافت کنید:

{
  "challenge": String,
  "rpId": String,
  "userVerification": "",
  "timeout": 1800000
}

جدول زیر برخی از پارامترهای مهم در شیء PublicKeyCredentialRequestOptions را توضیح می‌دهد:

پارامترها

توضیحات

challenge

یک چالش ایجاد شده توسط سرور در یک شیء ArrayBuffer . این برای جلوگیری از حملات بازپخش لازم است. هرگز یک چالش را دو بار در یک پاسخ نپذیرید. آن را یک توکن CSRF در نظر بگیرید.

rpId

شناسه RP یک دامنه است. یک وب‌سایت می‌تواند دامنه یا پسوند قابل ثبت خود را مشخص کند. این مقدار باید با پارامتر rp.id که هنگام ایجاد کلید عبور استفاده شده است، مطابقت داشته باشد.

  • در مرحله بعد، باید یک شیء PasswordOption() ایجاد کنید تا تمام رمزهای عبور ذخیره شده در ارائه دهنده رمز عبور خود را از طریق API مدیریت اعتبار برای این حساب کاربری بازیابی کند. در داخل متد getSavedCredentials() ، TODO را پیدا کرده و با موارد زیر جایگزین کنید:

ورود به سیستم ViewModel.kt

TODO("Create a PasswordOption to retrieve all the associated user's password")

val getPasswordOption = GetPasswordOption()

این موارد را در یک GetCredentialRequest ترکیب کنید.

ورود به سیستم ViewModel.kt

TODO("Combine requests into a GetCredentialRequest")
    val request = GetCredentialRequest(
        listOf(
            getPublicKeyCredentialOption,
            getPasswordOption
        )
    )

دریافت اعتبارنامه

در مرحله بعد، برای بازیابی اعتبارنامه‌های مرتبط، باید درخواست getCredential() را با تمام گزینه‌های فوق فراخوانی کنید:

ورود به سیستم

try {
    TODO("Call getCredential() with required credential options")
    val result = getCredential(request)

    val data = when (result.credential) {
        is PublicKeyCredential -> {
            val cred = result.credential as PublicKeyCredential
            DataProvider.setSignedInThroughPasskeys(true)
            "Passkey: ${cred.authenticationResponseJson}"
        }

        is PasswordCredential -> {
            val cred = result.credential as PasswordCredential
            DataProvider.setSignedInThroughPasskeys(false)
            "Got Password - User:${cred.id} Password: ${cred.password}"
        }

        is CustomCredential -> {
            //If you are also using any external sign-in libraries, parse them here with the utility functions provided.
            null
        }

        else -> null
    }

    TODO("Complete the authentication process after validating the public key credential to your server and let the user in.")
    } catch (e: Exception) {
        Log.e("Auth", "getCredential failed with exception: " + e.message.toString())
        _signInError.value =
            "An error occurred while authenticating: " + e.message.toString()
    } finally {
        _isLoading.value = false
    }
  • شما اطلاعات مورد نیاز را به getCredential() ارسال می‌کنید. این تابع لیستی از گزینه‌های اعتبارنامه و یک زمینه فعالیت را برای رندر کردن گزینه‌های موجود در برگه پایینی در آن زمینه دریافت می‌کند.
  • پس از موفقیت‌آمیز بودن درخواست، یک برگه پایین صفحه در صفحه خود مشاهده خواهید کرد که تمام اعتبارنامه‌های ایجاد شده برای حساب مرتبط را فهرست می‌کند.
  • اکنون کاربران می‌توانند هویت خود را از طریق بیومتریک یا قفل صفحه و غیره تأیید کنند تا اعتبارنامه انتخاب شده را تأیید کنند.
  • اگر اعتبارنامه انتخاب شده PublicKeyCredential است، پرچم setSignedInThroughPasskeys را روی true تنظیم کنید. در غیر این صورت، آن را روی false تنظیم کنید.

قطعه کد زیر شامل یک نمونه شیء PublicKeyCredential است:

{
  "id": String
  "rawId": String
  "type": "public-key",
  "response": {
    "clientDataJSON": String
    "authenticatorData": String
    "signature": String
    "userHandle": String
  }
}

جدول زیر جامع نیست، اما شامل پارامترهای مهم در شیء PublicKeyCredential است:

پارامترها

توضیحات

id

شناسه‌ی رمزگذاری‌شده‌ی Base64URL مربوط به اعتبارنامه‌ی رمز عبورِ احراز هویت‌شده.

rawId

یک نسخه شیء ArrayBuffer از شناسه اعتبارنامه.

response.clientDataJSON

یک شیء ArrayBuffer از داده‌های کلاینت. این فیلد حاوی اطلاعاتی مانند چالش و مبدایی است که سرور RP باید تأیید کند.

response.authenticatorData

یک شیء ArrayBuffer از داده‌های احراز هویت. این فیلد حاوی اطلاعاتی مانند شناسه RP است.

response.signature

یک شیء ArrayBuffer از امضا. این مقدار هسته اعتبارنامه است و باید روی سرور تأیید شود.

response.userHandle

یک شیء ArrayBuffer که شامل شناسه کاربری تنظیم شده در زمان ایجاد است. این مقدار می‌تواند به جای شناسه اعتبارنامه استفاده شود اگر سرور نیاز به انتخاب مقادیر شناسه‌ای که استفاده می‌کند داشته باشد، یا اگر backend بخواهد از ایجاد شاخص روی شناسه‌های اعتبارنامه جلوگیری کند.

  • در نهایت، شما باید فرآیند احراز هویت را تکمیل کنید. معمولاً پس از اینکه کاربر احراز هویت با رمز عبور را تکمیل کرد، برنامه یک اعتبارنامه کلید عمومی حاوی یک ادعای احراز هویت را به سرور ارسال می‌کند که ادعا را تأیید کرده و کاربر را احراز هویت می‌کند.

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

درون متد signInWithSavedCredentials() ، کامنت مربوطه را پیدا کرده و با کد زیر جایگزین کنید:

ورود به سیستم

TODO("Complete the authentication process after validating the public key credential to your server and let the user in.")
    if (data != null) {
        sendSignInResponseToServer()
        _navigationEvent.emit(NavigationEvent.NavigateToHome(signedInWithPasskeys = DataProvider.isSignedInThroughPasskeys()))
    }
  • sendSigninResponseToServer() مقدار true را برمی‌گرداند که نشان می‌دهد (ساختگی) سرور، کلید عمومی را برای استفاده‌های بعدی تأیید کرده است.
  • پس از ورود، کاربر را به صفحه اصلی هدایت می‌کنید.

برنامه را اجرا کنید و به مسیر ورود > ورود با رمز عبور/رمز عبور ذخیره شده بروید و با استفاده از اطلاعات کاربری ذخیره شده وارد سیستم شوید.

امتحانش کن

شما ایجاد کلیدهای عبور، ذخیره رمز عبور در Credential Manager و احراز هویت از طریق کلیدهای عبور یا رمز عبور ذخیره شده با استفاده از Credential Manager API را در برنامه اندروید خود پیاده‌سازی کرده‌اید.

۶. تبریک می‌گویم!

شما این آزمایشگاه کد را تمام کردید! اگر می‌خواهید راه‌حل نهایی را که در https://github.com/android/identity-samples/tree/main/CredentialManager موجود است، بررسی کنید.

اگر سوالی دارید، می‌توانید با استفاده از برچسب passkey ، از آنها در StackOverflow بپرسید.

بیشتر بدانید