আপনার প্রথম Android FIDO2 API

1. ভূমিকা

FIDO2 API কি?

FIDO2 API অ্যান্ড্রয়েড অ্যাপ্লিকেশনগুলিকে ব্যবহারকারীদের প্রমাণীকরণের উদ্দেশ্যে শক্তিশালী, সত্যায়িত পাবলিক কী-ভিত্তিক শংসাপত্র তৈরি এবং ব্যবহার করার অনুমতি দেয়৷ API একটি WebAuthn ক্লায়েন্ট বাস্তবায়ন প্রদান করে, যা BLE, NFC, এবং USB রোমিং অথেনটিকেটর (নিরাপত্তা কী) এর পাশাপাশি একটি প্ল্যাটফর্ম প্রমাণীকরণকারীর ব্যবহার সমর্থন করে, যা ব্যবহারকারীকে তাদের আঙ্গুলের ছাপ বা স্ক্রিনলক ব্যবহার করে প্রমাণীকরণ করতে দেয়।

আপনি যা নির্মাণ করবেন...

এই কোডল্যাবে, আপনি ফিঙ্গারপ্রিন্ট সেন্সর ব্যবহার করে একটি সাধারণ পুনরায় প্রমাণীকরণ কার্যকারিতা সহ একটি অ্যান্ড্রয়েড অ্যাপ তৈরি করতে যাচ্ছেন। "পুনরায় প্রমাণীকরণ" হল যখন একজন ব্যবহারকারী একটি অ্যাপে সাইন ইন করে, তারপর যখন তারা আপনার অ্যাপে ফিরে যায় বা যখন আপনার অ্যাপের একটি গুরুত্বপূর্ণ বিভাগে অ্যাক্সেস করার চেষ্টা করে তখন পুনরায় প্রমাণীকরণ করে । পরবর্তী কেসটিকে "স্টেপ-আপ প্রমাণীকরণ" হিসাবেও উল্লেখ করা হয়।

যা শিখবেন...

আপনি শিখবেন কিভাবে Android FIDO2 API-কে কল করতে হয় এবং বিভিন্ন উপলক্ষ পূরণের জন্য আপনি যে বিকল্পগুলি প্রদান করতে পারেন। এছাড়াও আপনি নির্দিষ্ট সর্বোত্তম অনুশীলনগুলি পুনঃলিখিত শিখবেন।

আপনার যা লাগবে...

  • একটি ফিঙ্গারপ্রিন্ট সেন্সর সহ অ্যান্ড্রয়েড ডিভাইস (এমনকি একটি ফিঙ্গারপ্রিন্ট সেন্সর ছাড়া, স্ক্রিনলক সমতুল্য ব্যবহারকারী যাচাইকরণ কার্যকারিতা প্রদান করতে পারে)
  • সর্বশেষ আপডেট সহ Android OS 7.0 বা তার পরে। একটি আঙ্গুলের ছাপ (বা স্ক্রিনলক) নিবন্ধন করা নিশ্চিত করুন।

2. সেট আপ করা হচ্ছে

সংগ্রহস্থল ক্লোন করুন

GitHub সংগ্রহস্থল দেখুন।

https://github.com/android/codelab-fido2

$ git clone https://github.com/android/codelab-fido2.git

আমরা কি বাস্তবায়ন করতে যাচ্ছি?

  • ব্যবহারকারীদের একটি "ব্যবহারকারী যাচাইকরণ প্ল্যাটফর্ম প্রমাণীকরণকারী" নিবন্ধন করতে দিন (ফিঙ্গারপ্রিন্ট সেন্সর সহ অ্যান্ড্রয়েড ফোন নিজেই একটি হিসাবে কাজ করবে)।
  • ব্যবহারকারীদের তাদের আঙ্গুলের ছাপ ব্যবহার করে অ্যাপে নিজেদেরকে পুনরায় প্রমাণীকরণ করতে দিন।

আপনি এখান থেকে কি তৈরি করতে যাচ্ছেন তার পূর্বরূপ দেখতে পারেন।

আপনার কোডল্যাব প্রকল্প শুরু করুন

সম্পূর্ণ অ্যাপটি https://webauthn-codelab.glitch.me এ সার্ভারে অনুরোধ পাঠায়। আপনি সেখানে একই অ্যাপের ওয়েব সংস্করণ চেষ্টা করতে পারেন।

c2234c42ba8a6ef1.png

আপনি অ্যাপটির নিজস্ব সংস্করণে কাজ করতে যাচ্ছেন।

  1. https://glitch.com/edit/#!/webauthn-codelab- এ ওয়েবসাইটের সম্পাদনা পৃষ্ঠায় যান।
  2. উপরের ডানদিকে কোণায় "রিমিক্স টু এডিট" বোতামটি খুঁজুন। বোতাম টিপে, আপনি কোডটি "ফর্ক" করতে পারেন এবং একটি নতুন প্রকল্প URL সহ আপনার নিজস্ব সংস্করণটি চালিয়ে যেতে পারেন৷ 9ef108869885e4ce.png
  3. উপরের বাম দিকে প্রকল্পের নামটি অনুলিপি করুন (আপনি এটিকে আপনার ইচ্ছামতো পরিবর্তন করতে পারেন)। c91d0d59c61021a4.png
  4. এটিকে .env ফাইলের HOSTNAME বিভাগে আটকান। 889b55b1cf74b894.png

3. ডিজিটাল সম্পদ লিঙ্কের সাথে আপনার অ্যাপ এবং একটি ওয়েবসাইট সংযুক্ত করুন৷

একটি Android অ্যাপে FIDO2 API ব্যবহার করতে, এটিকে একটি ওয়েবসাইটের সাথে সংযুক্ত করুন এবং তাদের মধ্যে শংসাপত্রগুলি ভাগ করুন৷ এটি করতে, ডিজিটাল অ্যাসেট লিঙ্কগুলি ব্যবহার করুন৷ আপনি আপনার ওয়েবসাইটে একটি ডিজিটাল সম্পদ লিঙ্ক JSON ফাইল হোস্ট করে এবং আপনার অ্যাপের ম্যানিফেস্টে ডিজিটাল সম্পদ লিঙ্ক ফাইলের একটি লিঙ্ক যোগ করে অ্যাসোসিয়েশন ঘোষণা করতে পারেন।

আপনার ডোমেনে .well-known/assetlinks.json হোস্ট করুন

আপনি একটি JSON ফাইল তৈরি করে আপনার অ্যাপ এবং ওয়েবসাইটের মধ্যে একটি সম্পর্ক নির্ধারণ করতে পারেন এবং এটি .well-known/assetlinks.json এ রাখতে পারেন। সৌভাগ্যবশত, আমাদের কাছে একটি সার্ভার কোড রয়েছে যা স্বয়ংক্রিয়ভাবে assetlinks.json ফাইলটি প্রদর্শন করে, শুধুমাত্র .env ফাইলে নিম্নোক্ত এনভায়রনমেন্ট প্যারামগুলি যোগ করার মাধ্যমে:

  • ANDROID_PACKAGENAME : আপনার অ্যাপের প্যাকেজের নাম (com.example.android.fido2)
  • ANDROID_SHA256HASH : আপনার স্বাক্ষর শংসাপত্রের SHA256 হ্যাশ৷

আপনার বিকাশকারী স্বাক্ষরকারী শংসাপত্রের SHA256 হ্যাশ পেতে, নীচের কমান্ডটি ব্যবহার করুন৷ ডিবাগ কীস্টোরের ডিফল্ট পাসওয়ার্ড হল "অ্যান্ড্রয়েড"।

$ keytool -exportcert -list -v -alias androiddebugkey -keystore ~/.android/debug.keystore

https://<your-project-name>.glitch.me/.well-known/assetlinks.json অ্যাক্সেস করে, আপনার এইরকম একটি JSON স্ট্রিং দেখতে হবে:

[{
  "relation": ["delegate_permission/common.handle_all_urls", "delegate_permission/common.get_login_creds"],
  "target": {
    "namespace": "web",
    "site": "https://<your-project-name>.glitch.me"
  }
}, {
  "relation": ["delegate_permission/common.handle_all_urls", "delegate_permission/common.get_login_creds"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.example.android.fido2",
    "sha256_cert_fingerprints": ["DE:AD:BE:EF:..."]
  }
}]

অ্যান্ড্রয়েড স্টুডিওতে প্রকল্পটি খুলুন

অ্যান্ড্রয়েড স্টুডিওর স্বাগত স্ক্রিনে "একটি বিদ্যমান অ্যান্ড্রয়েড স্টুডিও প্রকল্প খুলুন" এ ক্লিক করুন।

সংগ্রহস্থল চেক আউট ভিতরে "অ্যান্ড্রয়েড" ফোল্ডার নির্বাচন করুন .

1062875cf11ffb95.png

অ্যাপটিকে আপনার রিমিক্সের সাথে সংযুক্ত করুন

gradle.properties ফাইল খুলুন। ফাইলের নীচে, হোস্ট URLটিকে আপনার তৈরি করা গ্লিচ রিমিক্সে পরিবর্তন করুন।

// ...

# The URL of the server
host=https://<your-project-name>.glitch.me

এই মুহুর্তে, আপনার ডিজিটাল সম্পদ লিঙ্ক কনফিগারেশন সব সেট করা উচিত।

4. অ্যাপটি এখন কিভাবে কাজ করে তা দেখুন

অ্যাপটি এখন কীভাবে কাজ করে তা পরীক্ষা করে শুরু করা যাক। রান কনফিগারেশন কম্বোবক্সে "অ্যাপ-স্টার্ট" নির্বাচন করা নিশ্চিত করুন। আপনার সংযুক্ত Android ডিভাইসে অ্যাপটি চালু করতে "চালান" (কম্বোবক্সের পাশে সবুজ ত্রিভুজাকার) ক্লিক করুন।

29351fb97062b43c.png

আপনি যখন অ্যাপটি চালু করবেন তখন আপনি আপনার ব্যবহারকারীর নাম টাইপ করার জন্য স্ক্রীন দেখতে পাবেন। এটি UsernameFragment । প্রদর্শনের উদ্দেশ্যে, অ্যাপ এবং সার্ভার যেকোনো ব্যবহারকারীর নাম গ্রহণ করে। শুধু কিছু টাইপ করুন এবং "পরবর্তী" টিপুন।

bd9007614a9a3644.png

পরবর্তী স্ক্রীনটি আপনি দেখতে পাচ্ছেন AuthFragment । এখানে ব্যবহারকারী একটি পাসওয়ার্ড দিয়ে সাইন ইন করতে পারেন। আমরা পরে এখানে FIDO2 এর সাথে সাইন ইন করার জন্য একটি বৈশিষ্ট্য যোগ করব৷ আবার, প্রদর্শনের উদ্দেশ্যে, অ্যাপ এবং সার্ভার যেকোনো পাসওয়ার্ড গ্রহণ করে। শুধু কিছু টাইপ করুন এবং "সাইন ইন" টিপুন।

d9caba817a0a99bd.png

এটি এই অ্যাপটির শেষ স্ক্রিন, HomeFragment । আপাতত, আপনি এখানে শুধুমাত্র শংসাপত্রের একটি খালি তালিকা দেখতে পাচ্ছেন। "Reauth" টিপে আপনাকে আবার AuthFragment এ নিয়ে যাবে৷ "সাইন আউট" টিপে আপনাকে UsernameFragment ফিরিয়ে নিয়ে যাবে৷ "+" চিহ্ন সহ ভাসমান অ্যাকশন বোতামটি এখন কিছুই করে না, তবে এটি একটি নিবন্ধন শুরু করবে

আপনি একবার FIDO2 নিবন্ধন প্রবাহ প্রয়োগ করলে নতুন শংসাপত্র।

1cfcc6c884020e37.png

কোড শুরু করার আগে, এখানে একটি দরকারী কৌশল। অ্যান্ড্রয়েড স্টুডিওতে, নীচে "টুডো" টিপুন৷ এটি এই কোডল্যাবে সমস্ত TODO-এর একটি তালিকা দেখাবে৷ আমরা পরবর্তী বিভাগে প্রথম TODO দিয়ে শুরু করব।

e5a811bbc7cd7b30.png

5. একটি আঙ্গুলের ছাপ ব্যবহার করে একটি শংসাপত্র নিবন্ধন করুন৷

একটি আঙ্গুলের ছাপ ব্যবহার করে প্রমাণীকরণ সক্ষম করার জন্য, আপনাকে প্রথমে একটি ব্যবহারকারী যাচাইকারী প্ল্যাটফর্ম প্রমাণীকরণকারী দ্বারা উত্পন্ন একটি শংসাপত্র নিবন্ধন করতে হবে - একটি ডিভাইস-এমবেডেড প্রমাণীক যা বায়োমেট্রিক্স ব্যবহার করে ব্যবহারকারীকে যাচাই করে, যেমন একটি ফিঙ্গারপ্রিন্ট সেন্সর৷

37ce78fdf2759832.png

আমরা আগের বিভাগে দেখেছি, ভাসমান অ্যাকশন বোতাম এখন কিছুই করে না। আসুন দেখি কিভাবে আমরা একটি নতুন শংসাপত্র নিবন্ধন করতে পারি।

সার্ভার API কল করুন: /auth/registerRequest

AuthRepository.kt খুলুন এবং TODO(1) খুঁজুন।

এখানে, registerRequest হল সেই পদ্ধতি যা FAB চাপলে বলা হয়। আমরা এই পদ্ধতিটিকে সার্ভার API /auth/registerRequest কল করতে চাই। API সমস্ত PublicKeyCredentialCreationOptions সহ একটি ApiResult প্রদান করে যা ক্লায়েন্টকে একটি নতুন শংসাপত্র তৈরি করতে হবে।

তারপর আমরা বিকল্পগুলির সাথে getRegisterPendingIntent কল করতে পারি। এই FIDO2 API একটি আঙ্গুলের ছাপ ডায়ালগ খুলতে এবং একটি নতুন শংসাপত্র তৈরি করতে একটি Android PendingIntent ফেরত দেয় এবং আমরা সেই PendingIntent কলকারীকে ফেরত দিতে পারি।

পদ্ধতিটি তাহলে নিচের মত দেখাবে।

suspend fun registerRequest(): PendingIntent? {
  fido2ApiClient?.let { client ->
    try {
      val sessionId = dataStore.read(SESSION_ID)!!
      when (val apiResult = api.registerRequest(sessionId)) {
        ApiResult.SignedOutFromServer -> forceSignOut()
        is ApiResult.Success -> {
          if (apiResult.sessionId != null) {
            dataStore.edit { prefs ->
              prefs[SESSION_ID] = apiResult.sessionId
            }
          }
          val task = client.getRegisterPendingIntent(apiResult.data)
          return task.await()
        }
      }
    } catch (e: Exception) {
      Log.e(TAG, "Cannot call registerRequest", e)
    }
  }
  return null
}

রেজিস্ট্রেশনের জন্য ফিঙ্গারপ্রিন্ট ডায়ালগ খুলুন

HomeFragment.kt খুলুন এবং TODO(2) খুঁজুন।

এখানেই UI আমাদের AuthRepository থেকে অভিপ্রায় ফিরে পায়। এখানে, আমরা পূর্ববর্তী ধাপের ফলাফল হিসাবে পেন্ডিংইনটেন্ট চালু করতে createCredentialIntentLauncher সদস্য ব্যবহার করব। এটি শংসাপত্র তৈরির জন্য একটি ডায়ালগ খুলবে৷

binding.add.setOnClickListener {
  lifecycleScope.launch {
    val intent = viewModel.registerRequest()
    if (intent != null) {
      createCredentialIntentLauncher.launch(
        IntentSenderRequest.Builder(intent).build()
      )
    }
  }
}

নতুন শংসাপত্রের সাথে Activity Result পান

HomeFragment.kt খুলুন এবং TODO(3) খুঁজুন।

ফিঙ্গারপ্রিন্ট ডায়ালগ বন্ধ হওয়ার পরে এই handleCreateCredentialResult পদ্ধতিটি কল করা হয়। যদি একটি শংসাপত্র সফলভাবে তৈরি করা হয়, তাহলে ActivityResult-এর data সদস্যে শংসাপত্রের তথ্য থাকবে।

প্রথমত, আমাদের data থেকে একটি PublicKeyCredential বের করতে হবে। ডেটা ইন্টেন্টে Fido.FIDO2_KEY_CREDENTIAL_EXTRA কী সহ বাইট অ্যারের একটি অতিরিক্ত ক্ষেত্র রয়েছে। আপনি বাইট অ্যারেটিকে একটি PublicKeyCredential অবজেক্টে পরিণত করতে deserializeFromBytes নামে PublicKeyCredential এ একটি স্ট্যাটিক পদ্ধতি ব্যবহার করতে পারেন।

পরবর্তীতে এই শংসাপত্রের অবজেক্টের response সদস্যটি একটি AuthenticationErrorResponse কিনা চেক করুন। যদি এটি হয়, তাহলে শংসাপত্র তৈরি করার সময় একটি ত্রুটি ছিল; অন্যথায়, আমরা আমাদের ব্যাকএন্ডে শংসাপত্র পাঠাতে পারি।

সমাপ্ত পদ্ধতি এই মত দেখাবে:

private fun handleCreateCredentialResult(activityResult: ActivityResult) {
  val bytes = activityResult.data?.getByteArrayExtra(Fido.FIDO2_KEY_CREDENTIAL_EXTRA)
  when {
    activityResult.resultCode != Activity.RESULT_OK ->
      Toast.makeText(requireContext(), R.string.cancelled, Toast.LENGTH_LONG).show()
    bytes == null ->
      Toast.makeText(requireContext(), R.string.credential_error, Toast.LENGTH_LONG)
        .show()
    else -> {
      val credential = PublicKeyCredential.deserializeFromBytes(bytes)
      val response = credential.response
      if (response is AuthenticatorErrorResponse) {
        Toast.makeText(requireContext(), response.errorMessage, Toast.LENGTH_LONG)
          .show()
      } else {
        viewModel.registerResponse(credential)
      }
    }
  }
}

সার্ভার API কল করুন: /auth/registerResponse

AuthRepository.kt খুলুন এবং TODO(4) খুঁজুন।

UI সফলভাবে একটি নতুন শংসাপত্র তৈরি করার পরে এই registerResponse পদ্ধতিটি বলা হয় এবং আমরা এটি সার্ভারে ফেরত পাঠাতে চাই৷

PublicKeyCredential অবজেক্টের ভিতরে নতুন তৈরি হওয়া শংসাপত্র সম্পর্কে তথ্য রয়েছে। আমরা এখন আমাদের স্থানীয় কী এর আইডি মনে রাখতে চাই যাতে আমরা সার্ভারে নিবন্ধিত অন্যান্য কী থেকে এটিকে আলাদা করতে পারি। PublicKeyCredential অবজেক্টে, এর rawId প্রপার্টি নিন এবং toBase64 ব্যবহার করে একটি স্থানীয় স্ট্রিং ভেরিয়েবলে রাখুন।

এখন আমরা সার্ভারে তথ্য পাঠাতে প্রস্তুত। সার্ভার API কল করতে এবং প্রতিক্রিয়া ফেরত পাঠাতে api.registerResponse ব্যবহার করুন। প্রত্যাবর্তিত মানটিতে নতুনটি সহ সার্ভারে নিবন্ধিত সমস্ত শংসাপত্রের একটি তালিকা রয়েছে৷

অবশেষে, আমরা আমাদের DataStore ফলাফল সংরক্ষণ করতে পারি। শংসাপত্রের তালিকা একটি StringSet হিসাবে কী CREDENTIALS সাথে সংরক্ষণ করা উচিত। আপনি শংসাপত্রের তালিকাকে একটি StringSet রূপান্তর করতে toStringSet ব্যবহার করতে পারেন।

উপরন্তু, আমরা LOCAL_CREDENTIAL_ID কী দিয়ে শংসাপত্র আইডি সংরক্ষণ করি।

suspend fun registerResponse(credential: PublicKeyCredential) {
  try {
    val sessionId = dataStore.read(SESSION_ID)!!
    val credentialId = credential.rawId.toBase64()
    when (val result = api.registerResponse(sessionId, credential)) {
      ApiResult.SignedOutFromServer -> forceSignOut()
      is ApiResult.Success -> {
        dataStore.edit { prefs ->
          result.sessionId?.let { prefs[SESSION_ID] = it }
          prefs[CREDENTIALS] = result.data.toStringSet()
          prefs[LOCAL_CREDENTIAL_ID] = credentialId
        }
      }
    }
  } catch (e: ApiException) {
    Log.e(TAG, "Cannot call registerResponse", e)
  }
}

অ্যাপটি চালান, এবং আপনি FAB-এ ক্লিক করতে এবং একটি নতুন শংসাপত্র নিবন্ধন করতে সক্ষম হবেন।

7d64d9289c5a3cbc.png

6. একটি আঙ্গুলের ছাপ দিয়ে ব্যবহারকারীকে প্রমাণীকরণ করুন৷

আমাদের এখন অ্যাপ এবং সার্ভারে নিবন্ধিত একটি শংসাপত্র রয়েছে। আমরা এখন ব্যবহারকারীকে সাইন ইন করতে দিতে এটি ব্যবহার করতে পারি। আমরা AuthFragment এ ফিঙ্গারপ্রিন্ট সাইন-ইন বৈশিষ্ট্য যুক্ত করছি। যখন একজন ব্যবহারকারী এটিতে অবতরণ করেন, এটি একটি আঙ্গুলের ছাপ ডায়ালগ দেখায়। যখন প্রমাণীকরণ সফল হয়, ব্যবহারকারীকে HomeFragment পুনঃনির্দেশিত করা হয়।

সার্ভার API কল করুন: /auth/signinRequest

AuthRepository.kt খুলুন এবং TODO(5) খুঁজুন।

যখন AuthFragment খোলা হয় তখন এই signinRequest পদ্ধতিটি বলা হয়। এখানে, আমরা সার্ভারকে অনুরোধ করতে চাই এবং দেখতে চাই যে আমরা ব্যবহারকারীকে FIDO2 দিয়ে সাইন ইন করতে দিতে পারি কিনা।

প্রথমত, আমাদের সার্ভার থেকে PublicKeyCredentialRequestOptions পুনরুদ্ধার করতে হবে। সার্ভার API কল করতে api.signInRequest ব্যবহার করুন। ফিরে আসা ApiResult PublicKeyCredentialRequestOptions রয়েছে।

PublicKeyCredentialRequestOptions এর সাথে, আমরা ফিঙ্গারপ্রিন্ট ডায়ালগ খুলতে একটি PendingIntent তৈরি করতে FIDO2 API getSignIntent ব্যবহার করতে পারি।

অবশেষে, আমরা PendingIntent কে UI এ ফেরত দিতে পারি।

suspend fun signinRequest(): PendingIntent? {
  fido2ApiClient?.let { client ->
    val sessionId = dataStore.read(SESSION_ID)!!
    val credentialId = dataStore.read(LOCAL_CREDENTIAL_ID)
    if (credentialId != null) {
      when (val apiResult = api.signinRequest(sessionId, credentialId)) {
        ApiResult.SignedOutFromServer -> forceSignOut()
        is ApiResult.Success -> {
          val task = client.getSignPendingIntent(apiResult.data)
          return task.await()
        }
      }
    }
  }
  return null
}

দাবীর জন্য আঙ্গুলের ছাপ ডায়ালগ খুলুন

AuthFragment.kt খুলুন এবং TODO(6) খুঁজুন।

আমরা নিবন্ধনের জন্য যা করেছি এটি প্রায় একই রকম। আমরা signIntentLauncher সদস্যের সাথে ফিঙ্গারপ্রিন্ট ডায়ালগ চালু করতে পারি।

viewLifecycleOwner.lifecycleScope.launchWhenStarted {
  launch {
    viewModel.signinRequests.collect { intent ->
      signIntentLauncher.launch(
        IntentSenderRequest.Builder(intent).build()
      )
    }
  }
  launch {
    ...
  }
}

অ্যাক্টিভিটি রেজাল্ট পরিচালনা করুন

AuthFragment.kt খুলুন এবং TODO(7) খুঁজুন।

আবার, আমরা নিবন্ধনের জন্য যা করেছি তা একই। আমরা PublicKeyCredential এক্সট্র্যাক্ট করতে পারি, একটি ত্রুটি পরীক্ষা করতে পারি এবং এটিকে ViewModel-এ পাঠাতে পারি।

private fun handleSignResult(activityResult: ActivityResult) {
  val bytes = activityResult.data?.getByteArrayExtra(Fido.FIDO2_KEY_CREDENTIAL_EXTRA)
  when {
    activityResult.resultCode != Activity.RESULT_OK ->
      Toast.makeText(requireContext(), R.string.cancelled, Toast.LENGTH_SHORT).show()
    bytes == null ->
      Toast.makeText(requireContext(), R.string.auth_error, Toast.LENGTH_SHORT)
        .show()
    else -> {
      val credential = PublicKeyCredential.deserializeFromBytes(bytes)
      val response = credential.response
      if (response is AuthenticatorErrorResponse) {
        Toast.makeText(requireContext(), response.errorMessage, Toast.LENGTH_SHORT)
          .show()
      } else {
        viewModel.signinResponse(credential)
      }
    }
  }
}

সার্ভার API কল করুন: /auth/signinResponse

AuthRepository.kt খুলুন এবং TODO(8) খুঁজুন।

PublicKeyCredential অবজেক্টে keyHandle হিসাবে একটি শংসাপত্র আইডি রয়েছে। ঠিক যেমনটি আমরা রেজিস্ট্রেশন ফ্লোতে করেছি, আসুন এটিকে একটি স্থানীয় স্ট্রিং ভেরিয়েবলে সংরক্ষণ করি যাতে আমরা এটি পরে সংরক্ষণ করতে পারি।

আমরা এখন api.signinResponse সহ সার্ভার API কল করতে প্রস্তুত। প্রত্যাবর্তিত মানটিতে শংসাপত্রের একটি তালিকা রয়েছে।

এই সময়ে, সাইন-ইন সফল। আমাদের DataStore সমস্ত ফলাফল সংরক্ষণ করতে হবে। শংসাপত্রের তালিকাটি কী CREDENTIALS সাথে স্ট্রিংসেট হিসাবে সংরক্ষণ করা উচিত। আমরা উপরে যে স্থানীয় শংসাপত্র আইডিটি সংরক্ষণ করেছি তা LOCAL_CREDENTIAL_ID কী সহ একটি স্ট্রিং হিসাবে সংরক্ষণ করা উচিত।

অবশেষে, আমাদের সাইন-ইন অবস্থা আপডেট করতে হবে যাতে UI ব্যবহারকারীকে HomeFragment-এ রিডাইরেক্ট করতে পারে। signInStateMutable নামের SharedFlow-এ SignInState.SignedIn অবজেক্ট নির্গত করে এটি করা যেতে পারে। আমরা ব্যবহারকারীর শংসাপত্রগুলি আনতে refreshCredentials কল করতে চাই যাতে সেগুলি UI-তে তালিকাভুক্ত হয়৷

suspend fun signinResponse(credential: PublicKeyCredential) {
  try {
    val username = dataStore.read(USERNAME)!!
    val sessionId = dataStore.read(SESSION_ID)!!
    val credentialId = credential.rawId.toBase64()
    when (val result = api.signinResponse(sessionId, credential)) {
      ApiResult.SignedOutFromServer -> forceSignOut()
      is ApiResult.Success -> {
        dataStore.edit { prefs ->
          result.sessionId?.let { prefs[SESSION_ID] = it }
          prefs[CREDENTIALS] = result.data.toStringSet()
          prefs[LOCAL_CREDENTIAL_ID] = credentialId
        }
        signInStateMutable.emit(SignInState.SignedIn(username))
        refreshCredentials()
      }
    }
  } catch (e: ApiException) {
    Log.e(TAG, "Cannot call registerResponse", e)
  }
}

অ্যাপটি চালান এবং AuthFragment খুলতে "Reauth" এ ক্লিক করুন। আপনি এখন একটি ফিঙ্গারপ্রিন্ট ডায়ালগ দেখতে পাবেন যা আপনাকে আপনার আঙ্গুলের ছাপ দিয়ে সাইন ইন করতে অনুরোধ করবে।

45f81419f84952c8.png

অভিনন্দন! আপনি এখন রেজিস্ট্রেশন এবং সাইন-ইন করার জন্য Android-এ FIDO2 API ব্যবহার করতে শিখেছেন।

7. অভিনন্দন!

আপনি সফলভাবে কোডল্যাব শেষ করেছেন - আপনার প্রথম Android FIDO2 API

আপনি কি শিখেছেন

  • ব্যবহারকারী যাচাইকারী প্ল্যাটফর্ম প্রমাণীকরণকারী ব্যবহার করে কীভাবে একটি শংসাপত্র নিবন্ধন করবেন।
  • একটি নিবন্ধিত প্রমাণীকরণকারী ব্যবহার করে একজন ব্যবহারকারীকে কীভাবে প্রমাণীকরণ করবেন।
  • একটি নতুন প্রমাণীকরণকারী নিবন্ধনের জন্য উপলব্ধ বিকল্প।
  • একটি বায়োমেট্রিক সেন্সর ব্যবহার করে রিউথের জন্য UX সেরা অনুশীলন।

পরবর্তী ধাপ

  • একটি ওয়েবসাইটে অনুরূপ অভিজ্ঞতা তৈরি করতে শিখুন।

আপনি আপনার প্রথম WebAuthn কোডল্যাব ব্যবহার করে এটি শিখতে পারেন!

সম্পদ

আপনার সাহায্যের জন্য FIDO জোট থেকে Yuriy Ackermann কে বিশেষ ধন্যবাদ।