ক্রেডেনশিয়াল ম্যানেজার বলতে Android 14-এ চালু করা API-এর সেটকে বোঝায় যা ইউজারনেম-পাসওয়ার্ড, পাসকী ও ফেডারেটেড সাইন-ইন সমাধানের (যেমন, Google-এর মাধ্যমে সাইন-ইন করুন) মতো একাধিক সাইন-ইন পদ্ধতিকে সমর্থন করে। Credential Manager API কল করা হলে, Android সিস্টেম ডিভাইসে ইনস্টল করা সব ক্রেডেনশিয়াল প্রোভাইডার থেকে ক্রেডেনশিয়াল একত্রিত করে। এই ডকুমেন্টটি API-এর সেট বর্ণনা করে যা এইসব ক্রেডেনশিয়াল প্রদানকারীর জন্য ইন্টিগ্রেশন এন্ডপয়েন্ট প্রদান করে।
সেট-আপ করুন
আপনার ক্রেডেনশিয়াল প্রোভাইডারে কার্যকারিতা প্রয়োগ করার আগে, নিম্নলিখিত বিভাগে দেখানো সেট-আপের ধাপগুলি সম্পূর্ণ করুন।
ডিপেন্ডেন্সি ঘোষণা করা
ক্রেডেনশিয়াল ম্যানেজার লাইব্রেরির লেটেস্ট ভার্সন ব্যবহার করতে, আপনার অ্যাপ মডিউলের বিল্ড স্ক্রিপ্টে নিম্নলিখিত ডিপেন্ডেন্সি যোগ করুন:
কোটলিন
dependencies { implementation("androidx.credentials:credentials:1.7.0-alpha03") }
গ্রোভি
dependencies { implementation "androidx.credentials:credentials:1.7.0-alpha03" }
ম্যানিফেস্ট ফাইলে পরিষেবা এলিমেন্ট ঘোষণা করুন
আপনার অ্যাপের ম্যানিফেস্ট ফাইলে AndroidManifest.xml, একটি <service>
ঘোষণা অন্তর্ভুক্ত করুন যা androidx.credentials লাইব্রেরি থেকে
CredentialProviderService ক্লাসকে প্রসারিত করে, যেমনটি
নিম্নলিখিত উদাহরণে দেখানো হয়েছে।
<service android:name=".MyCredentialProviderService"
android:enabled="true"
android:exported="true"
android:label="My Credential Provider"
android:icon="@mipmap/ic_launcher"
android:permission="android.permission.BIND_CREDENTIAL_PROVIDER_SERVICE"
tools:targetApi="upside_down_cake">
<intent-filter>
<action android:name="android.service.credentials.CredentialProviderService"/>
</intent-filter>
<meta-data
android:name="android.credentials.provider"
android:resource="@xml/provider"/>
</service>
আগের উদাহরণে দেখানো অনুমতি ও ইনটেন্ট ফিল্টার ক্রেডেনশিয়াল ম্যানেজার ফ্লো প্রত্যাশিতভাবে কাজ করার জন্য অবিচ্ছেদ্য। এই অনুমতি প্রয়োজন যাতে শুধুমাত্র Android সিস্টেম এই পরিষেবার সাথে বাইন্ড করতে পারে। ক্রেডেনশিয়াল ম্যানেজার দ্বারা ব্যবহার করার জন্য ক্রেডেনশিয়াল প্রদানকারী হিসেবে এই পরিষেবার ডিসকভারেবিলিটির জন্য ইনটেন্ট ফিল্টার ব্যবহার করা হয়।
কাজ করে এমন ক্রেডেনশিয়ালের ধরন ঘোষণা করুন
আপনার res/xml ডিরেক্টরিতে, provider.xml নামে একটি নতুন ফাইল তৈরি করুন। এই
ফাইলে, লাইব্রেরিতে প্রতিটি ক্রেডেনশিয়াল ধরনের জন্য সংজ্ঞায়িত ধ্রুবকের মাধ্যমে আপনার পরিষেবা সমর্থন করে এমন ক্রেডেনশিয়াল ধরন ঘোষণা করুন। নিচের উদাহরণে, পরিষেবাটি চিরাচরিত পাসওয়ার্ডের পাশাপাশি পাসকীও সমর্থন করে, যার জন্য কনস্ট্যান্টগুলি
TYPE_PASSWORD_CREDENTIAL এবং
TYPE_PUBLIC_KEY_CREDENTIAL হিসেবে সংজ্ঞায়িত করা হয়েছে:
<credential-provider xmlns:android="http://schemas.android.com/apk/res/android">
<capabilities>
<capability name="android.credentials.TYPE_PASSWORD_CREDENTIAL" />
<capability name="androidx.credentials.TYPE_PUBLIC_KEY_CREDENTIAL" />
</capabilities>
</credential-provider>
আগের API লেভেলে, ক্রেডেনশিয়াল প্রদানকারীরা পাসওয়ার্ড ও অন্যান্য ডেটার জন্য অটোফিলের মতো API-এর সাথে ইন্টিগ্রেট করে। এইসব পরিষেবা প্রদানকারী একই ইন্টার্নাল ইনফ্রাস্ট্রাকচার ব্যবহার করে আগে থেকে থাকা ক্রেডেনশিয়ালের ধরন স্টোর করতে পারে এবং পাসকী সহ অন্যান্য ক্রেডেনশিয়াল স্টোর করার জন্য এটি আরও বাড়াতে পারে।
প্রোভাইডারের সাথে ইন্টার্যাকশনের জন্য দুই-পর্যায়ের পদ্ধতি
ক্রেডেনশিয়াল ম্যানেজার দুটি পর্যায়ে ক্রেডেনশিয়াল প্রদানকারীর সাথে ইন্টার্যাক্ট করে:
- প্রথম ধাপ হল শুরু/কোয়েরি ধাপ যেখানে সিস্টেম ক্রেডেনশিয়াল প্রোভাইডার পরিষেবার সাথে বাইন্ড করে এবং
Begin…অনুরোধের সাথেonBeginGetCredentialRequest(),onBeginCreateCredentialRequest()অথবাonClearCredentialStateRequest()পদ্ধতিকে ইনভোক করে। প্রদানকারীকে অবশ্যই এইসব অনুরোধ প্রসেস করতে হবে এবংBegin…টি উত্তর দিতে হবে, অ্যাকাউন্ট সিলেক্টরে দেখানোর জন্য ভিজ্যুয়াল বিকল্পের প্রতিনিধিত্ব করে এমন এন্ট্রি দিয়ে সেগুলি পূরণ করতে হবে। প্রতিটি এন্ট্রিতে একটিPendingIntentসেট থাকতে হবে। - ব্যবহারকারী কোনও এন্ট্রি বেছে নিলে, বেছে নেওয়ার পর্ব শুরু হয় এবং
এন্ট্রির সাথে যুক্ত
PendingIntentফায়ার হয়ে যায়, যার ফলে সংশ্লিষ্ট প্রোভাইডার অ্যাক্টিভিটি শুরু হয়। ব্যবহারকারী এই অ্যাক্টিভিটির সাথে ইন্টার্যাক্ট করা শেষ করলে, ক্রেডেনশিয়াল প্রদানকারীকে অ্যাক্টিভিটি শেষ করার আগে অ্যাক্টিভিটির ফলাফলে উত্তর সেট করতে হবে। এই উত্তরটি তারপর ক্লায়েন্ট অ্যাপে পাঠানো হয় যা ক্রেডেনশিয়াল ম্যানেজারকে আহ্বান করে।
পাসকী তৈরি করা ম্যানেজ করুন
পাসকী তৈরি করার জন্য কোয়েরি ম্যানেজ করা
কোনও ক্লায়েন্ট অ্যাপ পাসকী তৈরি করতে এবং ক্রেডেনশিয়াল প্রোভাইডারের সাথে এটি স্টোর করতে চাইলে, তারা createCredential API কল করে। আপনার ক্রেডেনশিয়াল প্রদানকারী পরিষেবায় এই
অনুরোধ ম্যানেজ করতে, যাতে পাসকী আপনার স্টোরেজে সেভ করা থাকে, তার জন্য নিম্নলিখিত বিভাগে দেখানো ধাপগুলি সম্পূর্ণ করুন।
- আপনার পরিষেবায়
onBeginCreateCredentialRequest()পদ্ধতি ওভাররাইড করুন যাCredentialProviderServiceথেকে এক্সটেন্ড করা হয়েছে। BeginCreateCredentialRequestহ্যান্ডেল করতে, সংশ্লিষ্টBeginCreateCredentialResponseতৈরি করুন এবং কলব্যাকের মাধ্যমে এটি পাস করুন।BeginCreateCredentialResponseতৈরি করার সময়, প্রয়োজনীয়CreateEntriesযোগ করুন। প্রতিটিCreateEntry-এর সাথে এমন একটি অ্যাকাউন্ট সম্পর্কিত থাকতে হবে যেখানে ক্রেডেনশিয়াল সেভ করা যাবে এবং অন্যান্য প্রয়োজনীয় মেটাডেটার সাথেPendingIntentসেট করা থাকতে হবে।
নিম্নলিখিত উদাহরণ থেকে এইসব ধাপ কীভাবে প্রয়োগ করবেন তা জানুন।
override fun onBeginCreateCredentialRequest(
request: BeginCreateCredentialRequest,
cancellationSignal: CancellationSignal,
callback: OutcomeReceiver<BeginCreateCredentialResponse, CreateCredentialException>,
) {
val response: BeginCreateCredentialResponse? = processCreateCredentialRequest(request)
if (response != null) {
callback.onResult(response)
} else {
callback.onError(CreateCredentialUnknownException())
}
}
fun processCreateCredentialRequest(request: BeginCreateCredentialRequest): BeginCreateCredentialResponse? {
when (request) {
is BeginCreatePublicKeyCredentialRequest -> {
// Request is passkey type
return handleCreatePasskeyQuery(request)
}
}
// Request not supported
return null
}
private fun handleCreatePasskeyQuery(
request: BeginCreatePublicKeyCredentialRequest
): BeginCreateCredentialResponse {
// Adding two create entries - one for storing credentials to the 'Personal'
// account, and one for storing them to the 'Family' account. These
// accounts are local to this sample app only.
val createEntries: MutableList<CreateEntry> = mutableListOf()
createEntries.add(
CreateEntry(
PERSONAL_ACCOUNT_ID,
createNewPendingIntent(PERSONAL_ACCOUNT_ID, CREATE_PASSKEY_INTENT)
)
)
createEntries.add(
CreateEntry(
FAMILY_ACCOUNT_ID,
createNewPendingIntent(FAMILY_ACCOUNT_ID, CREATE_PASSKEY_INTENT)
)
)
return BeginCreateCredentialResponse(createEntries)
}
private fun createNewPendingIntent(accountId: String, action: String): PendingIntent {
val intent = Intent(action).setPackage(PACKAGE_NAME)
// Add your local account ID as an extra to the intent, so that when
// user selects this entry, the credential can be saved to this
// account
intent.putExtra(EXTRA_KEY_ACCOUNT_ID, accountId)
return PendingIntent.getActivity(
applicationContext, UNIQUE_REQ_CODE,
intent,
(
PendingIntent.FLAG_MUTABLE
or PendingIntent.FLAG_UPDATE_CURRENT
)
)
}
আপনার PendingIntent নির্মাণে নিম্নলিখিত বিষয়গুলি মেনে চলতে হবে:
- প্রয়োজনীয় বায়োমেট্রিক প্রম্পট, কনফার্মেশন বা বাছাই দেখানোর জন্য সংশ্লিষ্ট অ্যাক্টিভিটি সেট-আপ করতে হবে।
- সংশ্লিষ্ট অ্যাক্টিভিটি চালু করার সময় প্রদানকারীর প্রয়োজনীয় ডেটা, আপনার
PendingIntentতৈরি করার জন্য ব্যবহৃত ইনটেন্টে অতিরিক্ত হিসেবে সেট করতে হবে, যেমন তৈরি করার ফ্লোতেaccountId। - আপনার
PendingIntentঅবশ্যইPendingIntent.FLAG_MUTABLEফ্ল্যাগ দিয়ে তৈরি করতে হবে যাতে সিস্টেম ইনটেন্ট এক্সট্রাতে চূড়ান্ত অনুরোধ যোগ করতে পারে। - আপনার
PendingIntent-এPendingIntent.FLAG_ONE_SHOTফ্ল্যাগ থাকলে চলবে না, কারণ ব্যবহারকারী কোনও এন্ট্রি বেছে নিয়ে, ফিরে গিয়ে আবার সেটি বেছে নিতে পারেন, যার ফলেPendingIntentদু'বার ফায়ার হবে। - আপনার
PendingIntent-এ অবশ্যই একটি অনন্য অনুরোধ কোড থাকতে হবে যাতে প্রতিটি এন্ট্রির নিজস্বPendingIntentথাকতে পারে।
পাসকী তৈরির অনুরোধের জন্য এন্ট্রি বেছে নেওয়ার বিষয়টি ম্যানেজ করুন
- ব্যবহারকারী আগে থেকে পূরণ করা
CreateEntryবেছে নিলে, সংশ্লিষ্টPendingIntentচালু করা হয় এবং সংশ্লিষ্ট প্রদানকারীActivityতৈরি করা হয়। - আপনার অ্যাক্টিভিটির
onCreateপদ্ধতি চালু হওয়ার পরে, সংশ্লিষ্ট ইনটেন্ট অ্যাক্সেস করুন এবংProviderCreateCredentialRequestপেতেPendingIntentHanderক্লাসে এটি পাস করুন। - অনুরোধ থেকে
requestJson,callingAppInfoএবংclientDataHashএক্সট্র্যাক্ট করুন। - ইনটেন্ট এক্সট্রা থেকে স্থানীয়
accountIdএক্সট্র্যাক্ট করুন। এটি একটি স্যাম্পেল অ্যাপ নির্দিষ্ট প্রয়োগ এবং এর প্রয়োজন নেই। এই অ্যাকাউন্ট আইডি ব্যবহার করে এই নির্দিষ্ট অ্যাকাউন্ট আইডির জন্য এই ক্রেডেনশিয়াল সেভ করা যাবে। requestJsonযাচাই করুন। নিচের উদাহরণে, ইনপুট JSON-কে WebAuthn স্পেসিফিকেশন অনুযায়ী স্ট্রাকচার্ড ক্লাসে পরিবর্তন করতে,PublicKeyCredentialCreationOptions-এর মতো লোকাল ডেটা ক্লাস ব্যবহার করা হয়। ক্রেডেনশিয়াল প্রোভাইডার হিসেবে, আপনি এটি নিজের পার্সার দিয়ে পরিবর্তন করতে পারবেন।- কলটি যদি কোনও নেটিভ Android অ্যাপ থেকে করা হয়, তাহলে কলিং অ্যাপের জন্য অ্যাসেট-লিঙ্ক চেক করুন।
- যাচাইকরণ প্রম্পট দেখান। নিচের উদাহরণে Android Biometric API ব্যবহার করা হয়েছে।
- যাচাইকরণ সম্পূর্ণ হলে, একটি
credentialIdএবং একটি কী পেয়ার জেনারেট করুন। callingAppInfo.packageName-এর বিপরীতে আপনার লোকাল ডেটাবেসে ব্যক্তিগত কী সেভ করুন।- Web Authentication API JSON রেসপন্স তৈরি করুন যাতে
সর্বজনীন কী ও
credentialIdথাকে। নিচের উদাহরণেAuthenticatorAttestationResponseএবংFidoPublicKeyCredential-এর মতো লোকাল ইউটিলিটি ক্লাস ব্যবহার করা হয়েছে যা আগে উল্লেখ করা স্পেসিফিকেশনের ভিত্তিতে JSON তৈরি করতে সাহায্য করে। ক্রেডেনশিয়াল প্রদানকারী হিসেবে, আপনি এইসব ক্লাসকে আপনার নিজস্ব বিল্ডার দিয়ে পরিবর্তন করতে পারবেন। - উপরে তৈরি করা JSON-এর সাহায্যে একটি
CreatePublicKeyCredentialResponseতৈরি করো। CreatePublicKeyCredentialResponse-কেIntent-এ অতিরিক্ত হিসেবে সেট করুনPendingIntentHander.setCreateCredentialResponse()-এর মাধ্যমে এবং সেই ইনটেন্টকে অ্যাক্টিভিটির ফলাফল হিসেবে সেট করুন।- অ্যাক্টিভিটি শেষ করুন।
নিচের কোডের উদাহরণে এই ধাপগুলি দেখানো হয়েছে। onCreate() চালু হয়ে গেলে,
আপনার অ্যাক্টিভিটি ক্লাসে এই কোড ম্যানেজ করতে হবে।
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
// ...
val request =
PendingIntentHandler.retrieveProviderCreateCredentialRequest(intent)
val accountId = intent.getStringExtra(CredentialsRepo.EXTRA_KEY_ACCOUNT_ID)
if (request != null && request.callingRequest is CreatePublicKeyCredentialRequest) {
val publicKeyRequest: CreatePublicKeyCredentialRequest =
request.callingRequest as CreatePublicKeyCredentialRequest
createPasskey(
publicKeyRequest.requestJson,
request.callingAppInfo,
publicKeyRequest.clientDataHash,
accountId
)
}
}
@SuppressLint("RestrictedApi")
fun createPasskey(
requestJson: String,
callingAppInfo: CallingAppInfo?,
clientDataHash: ByteArray?,
accountId: String?
) {
val request = PublicKeyCredentialCreationOptions(requestJson)
val biometricPrompt = BiometricPrompt(
this,
{ }, // Pass in your own executor
object : AuthenticationCallback() {
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
super.onAuthenticationError(errorCode, errString)
finish()
}
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
finish()
}
@RequiresApi(VERSION_CODES.P)
override fun onAuthenticationSucceeded(
result: AuthenticationResult
) {
super.onAuthenticationSucceeded(result)
// Generate a credentialId
val credentialId = ByteArray(32)
SecureRandom().nextBytes(credentialId)
// Generate a credential key pair
val spec = ECGenParameterSpec("secp256r1")
val keyPairGen = KeyPairGenerator.getInstance("EC")
keyPairGen.initialize(spec)
val keyPair = keyPairGen.genKeyPair()
// Save passkey in your database as per your own implementation
// Create AuthenticatorAttestationResponse object to pass to
// FidoPublicKeyCredential
val response = AuthenticatorAttestationResponse(
requestOptions = request,
credentialId = credentialId,
credentialPublicKey = getPublicKeyFromKeyPair(keyPair),
origin = appInfoToOrigin(callingAppInfo!!),
up = true,
uv = true,
be = true,
bs = true,
packageName = callingAppInfo.packageName
)
val credential = FidoPublicKeyCredential(
rawId = credentialId,
response = response,
authenticatorAttachment = "", // Add your authenticator attachment
)
val result = Intent()
val createPublicKeyCredResponse =
CreatePublicKeyCredentialResponse(credential.json())
// Set the CreateCredentialResponse as the result of the Activity
PendingIntentHandler.setCreateCredentialResponse(
result,
createPublicKeyCredResponse
)
setResult(RESULT_OK, result)
finish()
}
}
)
val promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Use your screen lock")
.setSubtitle("Create passkey for ${request.rp.name}")
.setAllowedAuthenticators(
BiometricManager.Authenticators.BIOMETRIC_STRONG
/* or BiometricManager.Authenticators.DEVICE_CREDENTIAL */
)
.build()
biometricPrompt.authenticate(promptInfo)
}
@RequiresApi(VERSION_CODES.P)
fun appInfoToOrigin(info: CallingAppInfo): String {
val cert = info.signingInfo.apkContentsSigners[0].toByteArray()
val md = MessageDigest.getInstance("SHA-256")
val certHash = md.digest(cert)
// This is the format for origin
return "android:apk-key-hash:${b64Encode(certHash)}"
}
পাসওয়ার্ড তৈরির অনুরোধের জন্য কোয়েরি ম্যানেজ করা
পাসওয়ার্ড তৈরির অনুরোধের জন্য কোয়েরি ম্যানেজ করতে, নিম্নলিখিত ধাপগুলি অনুসরণ করুন:
- আগের বিভাগে উল্লেখ করা আপনার
processCreateCredentialRequest()পদ্ধতির মধ্যে, পাসওয়ার্ড সংক্রান্ত অনুরোধ ম্যানেজ করার জন্য সুইচ ব্লকের মধ্যে আরেকটি কেস যোগ করুন। BeginCreateCredentialResponseতৈরি করার সময়, প্রয়োজনীয়CreateEntriesযোগ করুন।- প্রতিটি
CreateEntryএমন একটি অ্যাকাউন্টের সাথে সম্পর্কিত হতে হবে যেখানে ক্রেডেনশিয়াল সেভ করা যাবে এবং অন্যান্য মেটাডেটার সাথে অবশ্যই একটিPendingIntentসেট করা থাকতে হবে।
এইসব ধাপ কীভাবে প্রয়োগ করবেন তা নিম্নলিখিত উদাহরণ থেকে দেখুন:
fun processCreateCredentialRequest(
request: BeginCreateCredentialRequest
): BeginCreateCredentialResponse? {
when (request) {
is BeginCreatePublicKeyCredentialRequest -> {
// Request is passkey type
return handleCreatePasskeyQuery(request)
}
is BeginCreatePasswordCredentialRequest -> {
// Request is password type
return handleCreatePasswordQuery(request)
}
}
return null
}
@RequiresApi(VERSION_CODES.M)
private fun handleCreatePasswordQuery(
request: BeginCreatePasswordCredentialRequest
): BeginCreateCredentialResponse {
val createEntries: MutableList<CreateEntry> = mutableListOf()
// Adding two create entries - one for storing credentials to the 'Personal'
// account, and one for storing them to the 'Family' account. These
// accounts are local to this sample app only.
createEntries.add(
CreateEntry(
PERSONAL_ACCOUNT_ID,
createNewPendingIntent(PERSONAL_ACCOUNT_ID, CREATE_PASSWORD_INTENT)
)
)
createEntries.add(
CreateEntry(
FAMILY_ACCOUNT_ID,
createNewPendingIntent(FAMILY_ACCOUNT_ID, CREATE_PASSWORD_INTENT)
)
)
return BeginCreateCredentialResponse(createEntries)
}
পাসওয়ার্ড তৈরির অনুরোধের জন্য এন্ট্রি বেছে নেওয়ার বিষয়টি ম্যানেজ করুন
ব্যবহারকারী কোনও পপুলেট করা CreateEntry বেছে নিলে, সংশ্লিষ্ট
PendingIntent এক্সিকিউট হয় এবং অ্যাসোসিয়েট করা অ্যাক্টিভিটি দেখায়। onCreate-এ পাস করা সংশ্লিষ্ট ইনটেন্ট অ্যাক্সেস করুন এবং ProviderCreateCredentialRequest পদ্ধতি পেতে এটি PendingIntentHander ক্লাসে পাস করুন।
এই প্রসেস কীভাবে প্রয়োগ করতে হয় তা নিচের উদাহরণ থেকে বুঝতে পারবেন। এই কোডটি আপনার অ্যাক্টিভিটির onCreate() পদ্ধতিতে
ম্যানেজ করতে হবে।
val createRequest = PendingIntentHandler.retrieveProviderCreateCredentialRequest(intent)
val accountId = intent.getStringExtra(CredentialsRepo.EXTRA_KEY_ACCOUNT_ID)
if (createRequest == null) {
return
}
val request: CreatePasswordRequest = createRequest.callingRequest as CreatePasswordRequest
// Fetch the ID and password from the request and save it in your database
mDatabase.addNewPassword(
PasswordInfo(
request.id,
request.password,
createRequest.callingAppInfo.packageName
)
)
// Set the final response back
val result = Intent()
val response = CreatePasswordResponse()
PendingIntentHandler.setCreateCredentialResponse(result, response)
setResult(Activity.RESULT_OK, result)
finish()
ব্যবহারকারীর সাইন-ইন ম্যানেজ করা
ব্যবহারকারীর সাইন-ইন নিম্নলিখিত ধাপের মাধ্যমে ম্যানেজ করা হয়:
- কোনও ক্লায়েন্ট অ্যাপ ব্যবহারকারীকে সাইন-ইন করানোর চেষ্টা করলে, এটি একটি
GetCredentialRequestইনস্ট্যান্স তৈরি করে। - Android ফ্রেমওয়ার্ক এই পরিষেবাগুলির সাথে বাইন্ড করার মাধ্যমে সব প্রযোজ্য ক্রেডেনশিয়াল প্রোভাইডারকে এই অনুরোধ পাঠায়।
- প্রোভাইডার পরিষেবা তখন একটি
BeginGetCredentialRequestপায় যার মধ্যেBeginGetCredentialOption-এর একটি তালিকা থাকে, যার প্রতিটিতে প্যারামিটার থাকে যা ম্যাচিং ক্রেডেনশিয়াল ফিরিয়ে আনতে ব্যবহার করা যেতে পারে।
আপনার ক্রেডেনশিয়াল প্রদানকারী পরিষেবায় এই অনুরোধ ম্যানেজ করতে, নিম্নলিখিত ধাপগুলি সম্পূর্ণ করুন:
অনুরোধ ম্যানেজ করতে
onBeginGetCredentialRequest()পদ্ধতি ওভাররাইড করুন। মনে রাখবেন যে আপনার ক্রেডেনশিয়াল লক করা থাকলে, আপনি অবিলম্বে উত্তরে একটিAuthenticationActionসেট করতে এবং কলব্যাক চালু করতে পারবেন।private val unlockEntryTitle = "Authenticate to continue" override fun onBeginGetCredentialRequest( request: BeginGetCredentialRequest, cancellationSignal: CancellationSignal, callback: OutcomeReceiver<BeginGetCredentialResponse, GetCredentialException>, ) { if (isAppLocked()) { callback.onResult( BeginGetCredentialResponse( authenticationActions = mutableListOf( AuthenticationAction( unlockEntryTitle, createUnlockPendingIntent() ) ) ) ) return } try { response = processGetCredentialRequest(request) callback.onResult(response) } catch (e: GetCredentialException) { callback.onError(GetCredentialUnknownException()) } }যেসব পরিষেবা প্রদানকারীর ক্ষেত্রে কোনও
credentialEntriesফিরিয়ে দেওয়ার আগে ক্রেডেনশিয়াল আনলক করতে হয়, তাদের অবশ্যই একটি পেন্ডিং ইনটেন্ট সেট-আপ করতে হবে যা ব্যবহারকারীকে অ্যাপের আনলক ফ্লোতে নিয়ে যায়:private fun createUnlockPendingIntent(): PendingIntent { val intent = Intent(UNLOCK_INTENT).setPackage(PACKAGE_NAME) return PendingIntent.getActivity( applicationContext, UNIQUE_REQUEST_CODE, intent, ( PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) ) }আপনার স্থানীয় ডেটাবেস থেকে ক্রেডেনশিয়াল ফিরিয়ে আনুন এবং
CredentialEntriesব্যবহার করে সেগুলি সেট-আপ করুন যাতে সিলেক্টরে দেখানো যায়। পাসকী-র জন্য, আপনি ইনটেন্টে অতিরিক্ত হিসেবেcredentialIdসেট করতে পারেন যাতে ব্যবহারকারী এই এন্ট্রি বেছে নিলে এটি কোন ক্রেডেনশিয়ালের সাথে ম্যাপ করে তা জানা যায়।companion object { // These intent actions are specified for corresponding activities // that are to be invoked through the PendingIntent(s) private const val GET_PASSKEY_INTENT_ACTION = "PACKAGE_NAME.GET_PASSKEY" private const val GET_PASSWORD_INTENT_ACTION = "PACKAGE_NAME.GET_PASSWORD" } fun processGetCredentialRequest( request: BeginGetCredentialRequest ): BeginGetCredentialResponse { val callingPackageInfo = request.callingAppInfo val callingPackageName = callingPackageInfo?.packageName.orEmpty() val credentialEntries: MutableList<CredentialEntry> = mutableListOf() for (option in request.beginGetCredentialOptions) { when (option) { is BeginGetPasswordOption -> { credentialEntries.addAll( populatePasswordData( callingPackageName, option ) ) } is BeginGetPublicKeyCredentialOption -> { credentialEntries.addAll( populatePasskeyData( callingPackageInfo, option ) ) } else -> { Log.i(TAG, "Request not supported") } } } return BeginGetCredentialResponse(credentialEntries) }আপনার ডেটাবেস থেকে ক্রেডেনশিয়াল কোয়েরি করুন, পূরণ করার জন্য পাসকী ও পাসওয়ার্ড এন্ট্রি তৈরি করুন।
private fun populatePasskeyData( callingAppInfo: CallingAppInfo?, option: BeginGetPublicKeyCredentialOption ): List<CredentialEntry> { val passkeyEntries: MutableList<CredentialEntry> = mutableListOf() val request = PublicKeyCredentialRequestOptions(option.requestJson) // Get your credentials from database where you saved during creation flow val creds = getCredentialsFromInternalDb(request.rpId) val passkeys = creds.passkeys for (passkey in passkeys) { val data = Bundle() data.putString("credId", passkey.credId) passkeyEntries.add( PublicKeyCredentialEntry( context = applicationContext, username = passkey.username, pendingIntent = createNewPendingIntent( GET_PASSKEY_INTENT_ACTION, data ), beginGetPublicKeyCredentialOption = option, displayName = passkey.displayName, icon = passkey.icon ) ) } return passkeyEntries } // Fetch password credentials and create password entries to populate to the user private fun populatePasswordData( callingPackage: String, option: BeginGetPasswordOption ): List<CredentialEntry> { val passwordEntries: MutableList<CredentialEntry> = mutableListOf() // Get your password credentials from database where you saved during // creation flow val creds = getCredentialsFromInternalDb(callingPackage) val passwords = creds.passwords for (password in passwords) { passwordEntries.add( PasswordCredentialEntry( context = applicationContext, username = password.username, pendingIntent = createNewPendingIntent( GET_PASSWORD_INTENT ), beginGetPasswordOption = option, displayName = password.username, icon = password.icon ) ) } return passwordEntries } private fun createNewPendingIntent( action: String, extra: Bundle? = null ): PendingIntent { val intent = Intent(action).setPackage(PACKAGE_NAME) if (extra != null) { intent.putExtra("CREDENTIAL_DATA", extra) } return PendingIntent.getActivity( applicationContext, UNIQUE_REQUEST_CODE, intent, (PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT) ) }ক্রেডেনশিয়াল কোয়েরি ও পপুলেট করার পরে, ব্যবহারকারীর বেছে নেওয়া ক্রেডেনশিয়ালের জন্য আপনাকে বেছে নেওয়ার পর্ব ম্যানেজ করতে হবে, সেটি পাসকী বা পাসওয়ার্ড যাই হোক না কেন।
'পাসকী'-এর জন্য ব্যবহারকারীর পছন্দ ম্যানেজ করা
- সংশ্লিষ্ট অ্যাক্টিভিটির
onCreateপদ্ধতিতে, সংশ্লিষ্ট ইনটেন্ট ফিরিয়ে আনুন এবংPendingIntentHandler.retrieveProviderGetCredentialRequest()-এ পাস করুন। - উপরে পাওয়া অনুরোধ থেকে
GetPublicKeyCredentialOptionএক্সট্র্যাক্ট করুন। এরপর, এই বিকল্প থেকেrequestJsonএবংclientDataHashএক্সট্র্যাক্ট করুন। - ইনটেন্ট এক্সট্রা থেকে
credentialIdএক্সট্র্যাক্ট করুন, যা ক্রেডেনশিয়াল প্রদানকারী দ্বারা পপুলেট করা হয়েছিল যখন সংশ্লিষ্টPendingIntentসেট-আপ করা হয়েছিল। - উপরে অ্যাক্সেস করা অনুরোধের প্যারামিটার ব্যবহার করে আপনার স্থানীয় ডেটাবেস থেকে পাসকী এক্সট্র্যাক্ট করুন।
এক্সট্র্যাক্ট করা মেটাডেটা ও ব্যবহারকারী যাচাইকরণের মাধ্যমে পাসকীটি যে বৈধ তা নিশ্চিত করুন।
val getRequest = PendingIntentHandler.retrieveProviderGetCredentialRequest(intent) val publicKeyRequest = getRequest?.credentialOptions?.first() as GetPublicKeyCredentialOption val requestInfo = intent.getBundleExtra("CREDENTIAL_DATA") val credIdEnc = requestInfo?.getString("credId").orEmpty() // Get the saved passkey from your database based on the credential ID from the PublicKeyRequest val passkey = mDatabase.getPasskey(credIdEnc) // Decode the credential ID, private key and user ID val credId = b64Decode(credIdEnc) val privateKey = b64Decode(passkey.credPrivateKey) val uid = b64Decode(passkey.uid) val origin = appInfoToOrigin(getRequest.callingAppInfo) val packageName = getRequest.callingAppInfo.packageName validatePasskey( publicKeyRequest.requestJson, origin, packageName, uid, passkey.username, credId, privateKey )ব্যবহারকারীকে যাচাই করতে, একটি বায়োমেট্রিক প্রম্পট (বা অন্য কোনও অ্যাসারশন পদ্ধতি) দেখান। নিচে দেওয়া কোড স্নিপেট Android Biometric API ব্যবহার করে।
যাচাইকরণ সম্পূর্ণ হয়ে গেলে, W3 Web Authentication Assertion spec-এর উপর ভিত্তি করে JSON রেসপন্স তৈরি করুন। নিচে দেওয়া কোড স্নিপেটে,
AuthenticatorAssertionResponse-এর মতো সহায়ক ডেটা ক্লাস ব্যবহার করে স্ট্রাকচার্ড প্যারামিটার নেওয়া হয় এবং সেগুলিকে প্রয়োজনীয় JSON ফর্ম্যাটে কনভার্ট করা হয়। উত্তরে WebAuthn ক্রেডেনশিয়ালের ব্যক্তিগত কী থেকে পাওয়া ডিজিটাল স্বাক্ষর থাকে। সাইন-ইন করার আগে ব্যবহারকারীকে যাচাই করতে, রিলাইং পার্টির সার্ভার এই স্বাক্ষর যাচাই করতে পারে।উপরে জেনারেট করা JSON ব্যবহার করে একটি
PublicKeyCredentialতৈরি করুন এবং এটি একটি ফাইনালGetCredentialResponse-এ সেট করুন। এই অ্যাক্টিভিটির ফলাফলের উপর এই চূড়ান্ত উত্তর সেট করুন।
এইসব ধাপ কীভাবে প্রয়োগ করা যেতে পারে তা নিম্নলিখিত উদাহরণ থেকে বোঝা যাবে:
val request = PublicKeyCredentialRequestOptions(requestJson)
val privateKey: ECPrivateKey = convertPrivateKey(privateKeyBytes)
val biometricPrompt = BiometricPrompt(
this,
{ }, // Pass in your own executor
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationError(
errorCode: Int,
errString: CharSequence
) {
super.onAuthenticationError(errorCode, errString)
finish()
}
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
finish()
}
override fun onAuthenticationSucceeded(
result: BiometricPrompt.AuthenticationResult
) {
super.onAuthenticationSucceeded(result)
val response = AuthenticatorAssertionResponse(
requestOptions = request,
credentialId = credId,
origin = origin,
up = true,
uv = true,
be = true,
bs = true,
userHandle = uid,
packageName = packageName
)
val sig = Signature.getInstance("SHA256withECDSA")
sig.initSign(privateKey)
sig.update(response.dataToSign())
response.signature = sig.sign()
val credential = FidoPublicKeyCredential(
rawId = credId,
response = response,
authenticatorAttachment = "", // Add your authenticator attachment
)
val result = Intent()
val passkeyCredential = PublicKeyCredential(credential.json())
PendingIntentHandler.setGetCredentialResponse(
result, GetCredentialResponse(passkeyCredential)
)
setResult(RESULT_OK, result)
finish()
}
}
)
val promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Use your screen lock")
.setSubtitle("Use passkey for ${request.rpId}")
.setAllowedAuthenticators(
BiometricManager.Authenticators.BIOMETRIC_STRONG
/* or BiometricManager.Authenticators.DEVICE_CREDENTIAL */
)
.build()
biometricPrompt.authenticate(promptInfo)
পাসওয়ার্ড যাচাইকরণের জন্য ব্যবহারকারীর বেছে নেওয়া বিকল্প ম্যানেজ করা হচ্ছে
- আপনার সংশ্লিষ্ট অ্যাক্টিভিটিতে,
onCreate-এ পাস করা ইনটেন্ট অ্যাক্সেস করুন এবংPendingIntentHandlerব্যবহার করেProviderGetCredentialRequestএক্সট্র্যাক্ট করুন। ইনকামিং প্যাকেজের নামের জন্য পাসওয়ার্ড ক্রেডেনশিয়াল ফেরত পেতে অনুরোধে
GetPasswordOptionব্যবহার করুন।val getRequest = PendingIntentHandler.retrieveProviderGetCredentialRequest(intent) val passwordOption = getRequest?.credentialOptions?.first() as GetPasswordOption val username = passwordOption.allowedUserIds.first() // Fetch the credentials for the calling app package name val creds = mDatabase.getCredentials(callingAppInfo.packageName) val passwords = creds.passwords val it = passwords.iterator() var password = "" while (it.hasNext()) { val passwordItemCurrent = it.next() if (passwordItemCurrent.username == username) { password = passwordItemCurrent.password break } }উদ্ধার করা হয়ে গেলে, বেছে নেওয়া পাসওয়ার্ড ক্রেডেনশিয়ালের জন্য উত্তর সেট করুন।
// Set the response back val result = Intent() val passwordCredential = PasswordCredential(username, password) PendingIntentHandler.setGetCredentialResponse( result, GetCredentialResponse(passwordCredential) ) setResult(Activity.RESULT_OK, result) finish()
যাচাইকরণ অ্যাকশন এন্ট্রি বেছে নেওয়ার বিষয়টি ম্যানেজ করুন
আগে যেমন উল্লেখ করা হয়েছে, ক্রেডেনশিয়াল লক করা থাকলে ক্রেডেনশিয়াল প্রদানকারী একটি
AuthenticationAction সেট করতে পারে। ব্যবহারকারী এই এন্ট্রি বেছে নিলে, PendingIntent-এ সেট করা ইনটেন্ট অ্যাকশনের সাথে সম্পর্কিত অ্যাক্টিভিটি
ইনভোক করা হয়। ক্রেডেনশিয়াল প্রদানকারী তখন ক্রেডেনশিয়াল আনলক করার জন্য বায়োমেট্রিক
যাচাইকরণ ফ্লো বা একই ধরনের মেকানিজম দেখাতে পারে। সফল হলে,
ক্রেডেনশিয়াল প্রদানকারীকে অবশ্যই একটি BeginGetCredentialResponse তৈরি করতে হবে, ব্যবহারকারীর সাইন-ইন হ্যান্ডলিং যেভাবে উপরে বর্ণনা করা হয়েছে
তার অনুরূপ, কারণ ক্রেডেনশিয়াল এখন
আনলক করা হয়েছে। প্রস্তুত করা ইনটেন্ট ফলাফল হিসেবে সেট করা এবং অ্যাক্টিভিটি শেষ হওয়ার আগে
PendingIntentHandler.setBeginGetCredentialResponse() পদ্ধতির মাধ্যমে
এই উত্তর সেট করতে হবে।
ক্রেডেনশিয়াল সংক্রান্ত অনুরোধ মুছুন
কোনও ক্লায়েন্ট অ্যাপ ক্রেডেনশিয়াল বেছে নেওয়ার জন্য সেভ করা যেকোনও স্ট্যাটাস মুছে দেওয়ার অনুরোধ করতে পারে,
যেমন, কোনও ক্রেডেনশিয়াল প্রদানকারী আগে বেছে নেওয়া ক্রেডেনশিয়াল মনে রাখতে পারে এবং
পরের বার শুধু সেটিই দেখাতে পারে। কোনও ক্লায়েন্ট অ্যাপ এই API কল করে এবং
আশা করে যে স্টিকি সিলেকশন মুছে ফেলা হবে। আপনার ক্রেডেনশিয়াল প্রদানকারী পরিষেবা
onClearCredentialStateRequest() পদ্ধতি ওভাররাইড করে
এই অনুরোধ ম্যানেজ করতে পারে:
override fun onClearCredentialStateRequest(
request: ProviderClearCredentialStateRequest,
cancellationSignal: CancellationSignal,
callback: OutcomeReceiver<Void?, ClearCredentialException>
) {
// Delete any maintained state as appropriate.
}
আপনার পরিষেবা প্রদানকারীর সেটিংস পৃষ্ঠায় লিঙ্ক করার ক্ষমতা যোগ করুন
ব্যবহারকারীদের পাসওয়ার্ড,
পাসকী ও অটোফিল স্ক্রিন থেকে আপনার পরিষেবা প্রদানকারীর সেটিংস খোলার অনুমতি দিতে, ক্রেডেনশিয়াল প্রদানকারী অ্যাপকে
res/xml/provider.xml-এ credential-provider settingsActivity ম্যানিফেস্ট অ্যাট্রিবিউট
প্রয়োগ করতে হবে। এই অ্যাট্রিবিউট আপনাকে একটি ইনটেন্ট ব্যবহার করতে দেয় যাতে ব্যবহারকারী পাসওয়ার্ড,
পাসকী ও অটোফিল পরিষেবার তালিকায় কোনও পরিষেবা প্রদানকারীর নামে ক্লিক করলে আপনার অ্যাপের
নিজস্ব সেটিংস স্ক্রিন খুলে যায়। এই অ্যাট্রিবিউটের ভ্যালু সেটিংস স্ক্রিন থেকে লঞ্চ করা অ্যাক্টিভিটির নামের সাথে সেট করুন।
<credential-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:settingsSubtitle="Example settings provider name"
android:settingsActivity="com.example.SettingsActivity">
<capabilities>
<capability name="android.credentials.TYPE_PUBLIC_KEY_CREDENTIAL" />
</capabilities>
</credential-provider>
সেটিংস ইনটেন্ট
সেটিংস খোলা: android.settings.CREDENTIAL_PROVIDER ইনটেন্ট
একটি সেটিংস স্ক্রিন দেখায় যেখানে ব্যবহারকারী তার পছন্দের এবং
অতিরিক্ত ক্রেডেনশিয়াল প্রদানকারী বেছে নিতে পারেন।
পছন্দের ক্রেডেনশিয়াল পরিষেবা: ACTION_REQUEST_SET_AUTOFILL_SERVICE ইনটেন্ট আপনার ব্যবহারকারীকে পছন্দের পরিষেবা প্রদানকারী বেছে নেওয়ার স্ক্রিনে রিডাইরেক্ট করে। এই স্ক্রিনে বেছে নেওয়া পরিষেবা প্রদানকারী
পছন্দের ক্রেডেনশিয়াল ও অটোফিল পরিষেবা প্রদানকারী হয়ে যায়।
বিশেষ অধিকারপ্রাপ্ত অ্যাপের অনুমোদিত তালিকা পান
ওয়েব ব্রাউজারের মতো বিশেষ সুবিধা প্রাপ্ত অ্যাপ, ক্রেডেনশিয়াল ম্যানেজারের GetCredentialRequest() এবং CreatePublicKeyCredentialRequest() পদ্ধতিতে origin প্যারামিটার সেট করে অন্যান্য নির্ভরশীল পক্ষের হয়ে ক্রেডেনশিয়াল ম্যানেজার কল করে। এইসব অনুরোধ প্রসেস করতে,
ক্রেডেনশিয়াল প্রোভাইডার getOrigin()
API ব্যবহার করে origin ফিরিয়ে আনে।
origin ফিরিয়ে আনতে, ক্রেডেনশিয়াল প্রদানকারী অ্যাপকে
androidx.credentials.provider.CallingAppInfo's getOrigin() API-তে
বিশেষাধিকারপ্রাপ্ত ও বিশ্বস্ত কলারের তালিকা পাস করতে হবে। এই অনুমোদিত তালিকা
অবশ্যই একটি সঠিক JSON অবজেক্ট হতে হবে। origin ফেরত দেওয়া হয় যদি packageName এবং
signingInfo থেকে পাওয়া সার্টিফিকেট ফিঙ্গারপ্রিন্ট getOrigin() API-তে পাস করা privilegedAllowlist-এ
পাওয়া অ্যাপের সাথে মিলে যায়। origin ভ্যালু পাওয়ার পরে,
প্রোভাইডার অ্যাপের এটিকে একটি বিশেষাধিকার প্রাপ্ত কল হিসেবে বিবেচনা করা উচিত এবং
কলিং অ্যাপের সিগনেচার ব্যবহার করে origin গণনা করার পরিবর্তে
AuthenticatorResponse-এ origin ক্লায়েন্ট ডেটাতে সেট করা উচিত।
আপনি origin ফিরিয়ে আনলে, clientDataHash ব্যবহার করুন যা সরাসরি
CreatePublicKeyCredentialRequest() বা
GetPublicKeyCredentialOption()-এ দেওয়া আছে, স্বাক্ষর অনুরোধের সময় clientDataJSON অ্যাসেম্বল ও হ্যাশ করার
পরিবর্তে। JSON পার্সিং সংক্রান্ত সমস্যা এড়াতে, অ্যাটেস্টেশন ও অ্যাসারশন
উত্তরে clientDataJSON-এর জন্য একটি প্লেসহোল্ডার ভ্যালু সেট করুন। Google Password Manager, getOrigin()-এ কল করার জন্য সর্বজনীনভাবে উপলভ্য
অনুমতি তালিকা ব্যবহার করে। ক্রেডেনশিয়াল প্রদানকারী হিসেবে, আপনি এই তালিকা ব্যবহার করতে পারেন অথবা API-এর মাধ্যমে বর্ণিত JSON ফর্ম্যাটে আপনার নিজস্ব তালিকা প্রদান করতে পারেন। কোন তালিকা ব্যবহার করা হবে তা বেছে নেওয়ার দায়িত্ব প্রদানকারীর। থার্ড-পার্টি ক্রেডেনশিয়াল প্রদানকারীর সাথে
বিশেষ অ্যাক্সেস পেতে, থার্ড-পার্টির প্রদান করা
ডকুমেন্টেশন দেখুন।
কোনও ডিভাইসে পরিষেবা প্রদানকারী চালু করুন
ব্যবহারকারীকে অবশ্যই ডিভাইস সেটিংস > পাসওয়ার্ড ও অ্যাকাউন্ট > আপনার পরিষেবা প্রদানকারী > চালু বা বন্ধ করুন বিকল্পের মাধ্যমে পরিষেবা প্রদানকারীকে চালু করতে হবে।
fun createSettingsPendingIntent(): PendingIntent