يوضّح هذا الدليل بالتفصيل كيفية استخدام DigitalCredential API للحصول على أرقام هواتف تم تأكيدها للمستخدمين. تتضمّن العملية خطوتَين:
- طلب
TS.43 token: يطلب تطبيق العميل (الذي يُطلق عليه اسم "المُدقّق") رمزًا مميّزًا مؤقتًا من TS.43 من جهاز المستخدم.TS.43 tokenهي مستند تعريف صادر عن مشغّل شبكة الجوّال يمثّل هوية المستخدم. - استبدال الرمز المميز برقم هاتف: يتبادل الخلفية البرمجية لتطبيقك الرمز المميز
TS.43 tokenمع خدمة تجميع أو مشغّل شبكة جوّال للحصول على رقم هاتف المستخدم الذي تم إثبات ملكيته.
التوافق مع إصدارات Android
تتوافق واجهة برمجة التطبيقات الخاصة بإثبات ملكية رقم الهاتف مع الإصدار 10 من نظام التشغيل Android (المستوى 29 من واجهة برمجة التطبيقات) والإصدارات الأحدث.
المتطلّبات الأساسية
لتنفيذ عملية إثبات رقم الهاتف باستخدام DigitalCredential API، يجب أن يكون لديك حساب لدى جهة تجميع. يتفاعل المجمّع مع شركات النقل ويوفّر مساحة واجهة برمجة التطبيقات اللازمة لتطبيقك، وعادةً ما يكون ذلك كنقطة نهاية لواجهة برمجة تطبيقات سحابية قابلة للفوترة.
عليك أيضًا إضافة التبعيتَين التاليتَين إلى نص برمجة الإصدار في Gradle:
Kotlin
dependencies { implementation("androidx.credentials:credentials:1.6.0-rc02") implementation("androidx.credentials:credentials-play-services-auth:1.6.0-rc02") }
Groovy
dependencies { implementation "androidx.credentials:credentials:1.6.0-rc02" implementation "androidx.credentials:credentials-play-services-auth:1.6.0-rc02" }
التنفيذ
تتّبع العملية الشاملة الخطوات التالية بشكل عام:
- طلب مَعلمات DCQL (لغة طلب البحث عن المستندات الرقمية) من خدمة تجميع: اتّصِل بخدمة تجميع واحدة أو أكثر واطلب مجموعة من مَعلمات DCQL. تتيح لك DCQL تحديد بيانات الاعتماد الرقمية المحدّدة التي تحتاج إليها من كل جهة تجميع.
إنشاء طلب OpenID4VP: من الخلفية في تطبيقك، أنشئ طلب OpenID4VP، مع تضمين مَعلمات DCQL من خدمة التجميع. بعد ذلك، أرسِل طلب OpenID4VP إلى تطبيق العميل.
طلب الوصول إلى Credential Manager API: في تطبيق العميل، استخدِم واجهة Credential Manager API لإرسال طلب OpenID4VP إلى نظام التشغيل. في المقابل، ستتلقّى عنصر استجابة OpenID4VP يحتوي على
TS.43 Digital Credential. يتم تشفير بيانات الاعتماد هذه، ولا يمكن فك تشفيرها إلا من خلال خدمة التجميع المرتبطة بها. بعد تلقّي رمز شركة الاتصالات، أرسِل الردّ من تطبيق العميل إلى الخلفية الخاصة بالتطبيق.التحقّق من صحة الردّ: في الخلفية الخاصة بتطبيقك، تحقَّق من صحة الردّ الوارد من OpenID4VP.
الاستبدال برقم الهاتف: من الخلفية البرمجية لتطبيقك، أرسِل
TS.43 Digital Credentialإلى خدمة التجميع. يتحقّق موفّر خدمة التجميع من صحة بيانات الاعتماد ويعرض رقم الهاتف الذي تم تأكيده.
طلب مَعلمات DCQL من خدمة تجميع
من الخلفية البرمجية لتطبيقك، أرسِل طلبًا إلى خدمة التجميع للحصول على عنصر بيانات اعتماد Digital Credential Query Language (DCQL). احرص على تقديم قيمة nonce ورقم تعريف الطلب في طلبك. تعرض أداة التجميع عنصر بيانات اعتماد DCQL، الذي يتضمّن بنية مشابهة لما يلي:
{
// The credential ID is mapped to the request ID that is sent in your request to the aggregator.
"id": "aggregator1",
"format": "dc-authorization+sd-jwt",
"meta": {
"vct_values": [
"number-verification/device-phone-number/ts43"
],
"credential_authorization_jwt": "..."
},
"claims": [
{
"path": ["subscription_hint"],
"values": [1]
},
{
"path": ["phone_number_hint"],
"values": ["+14155552671"]
}
]
}
إنشاء طلب OpenID4VP
أولاً، من الخلفية الخاصة بتطبيقك، أنشئ عنصر dcql_query من خلال وضع عنصر بيانات اعتماد DCQL في مصفوفة credentials مضمّنة في عنصر dcql_query كما هو موضّح في المثال التالي:
"dcql_query": {
"credentials": [
"id": "aggregator1",
"format": "dc-authorization+sd-jwt",
"meta": {
"vct_values": [
"number-verification/device-phone-number/ts43"
],
"credential_authorization_jwt": "..."
},
"claims": [
{
"path": ["subscription_hint"],
"values": [1]
},
{
"path": ["phone_number_hint"],
"values": ["+14155552671"]
}
]
]
}
بعد ذلك، أنشئ طلب OpenID4VP بالبنية التالية:
{
"protocol": "openid4vp-v1-unsigned",
"data": {
"response_type": "vp_token",
"response_mode": "dc_api",
"nonce": "...",
"dcql_query": { ... }
}
}
protocol: يجب ضبطه علىopenid4vp-v1-unsignedلطلبات التحقّق من رقم الهاتف.-
response_typeوresponse_mode: ثوابت تشير إلى تنسيق الطلب بقيم ثابتةvp_tokenوdc_apiعلى التوالي. nonce: قيمة فريدة ينشئها الخلفية لكل طلب. يجب أن يتطابق الرقم الخاص في عنصر بيانات اعتماد DCQL الخاص بالمجمّع مع هذا الرقم الخاص.dcql_query: في هذه الحالة، استخدِم السمةdcql_queryلتحديد أنّه يتم طلبTS.43 Digital Credential. يمكنك أيضًا طلب مستندات تعريف رقمية أخرى هنا.
بعد ذلك، يمكنك تضمين طلب OpenID4VP في عنصر طلب بيانات من واجهة برمجة التطبيقات DigitalCredential وإرساله إلى تطبيق العميل.
{
"requests":
[
{
"protocol": "openid4vp-v1-unsigned",
"data": {
"response_type": "vp_token",
"response_mode": "dc_api",
"nonce": "...",
"dcql_query": { ... }
}
}
]
}
يوضّح المقتطف التالي كيفية إنشاء طلب DigitalCredential API:
def GenerateDCRequest():
credentials = []
aggregator1_dcql = call_aggregator_endpoint(nonce, "aggregator1", additional_params)
credentials.append(aggregator1_dcql) # You can optionally work with multiple
# aggregators, or request other types of credentials
val dc_request =
{
"requests":
[
{
"protocol": "openid4vp-v1-unsigned",
"data": {
"response_type": "vp_token",
"response_mode": "dc_api",
"nonce": "...",
"dcql_query": {"credentials": credentials}
}
}
]
}
return dc_request
استدعاء Credential Manager API
في تطبيق العميل، أرسِل طلب بيانات من واجهة برمجة التطبيقات إلى Credential Manager API، مع طلب DigitalCredential API الذي توفّره الخلفية في تطبيقك.
val requestJson = generateTs43DigitalCredentialRequestFromServer()
val digiCredOption = GetDigitalCredentialOption(requestJson = requestJson)
val getCredRequest = GetCredentialRequest(
listOf(digiCredOption)
)
coroutineScope.launch {
try {
val response = credentialManager.getCredential(
context = activityContext,
request = getCredRequest
)
val credential = response.credential
when (credential) {
is DigitalCredential -> {
val responseJson = credential.credentialJson
validateResponseOnServer(responseJson)
}
else -> {
// Catch any unrecognized credential type here.
Log.e(TAG, "Unexpected type of credential ${credential.type}")
}
}
} catch (e : GetCredentialException) {
// If user cancels the operation, the feature isn't available, or the
// SIM doesn't support the feature, a GetCredentialCancellationException
// will be returned. Otherwise, a GetCredentialUnsupportedException will
// be returned with details in the exception message.
handleFailure(e)
}
}
يتضمّن الردّ من DigitalCredential API الردّ من OpenID4VP. في ما يلي مثال على ملف JSON نموذجي خاص بشهادة اعتماد من نتيجة DigitalCredential:
{
"protocol": "openid4vp-v1-unsigned",
"data": {
"vp_token": {
"aggregator1": ["eyJhbGciOiAiRVMy..."] # The encrypted TS.43 Digital
# Credential in an array structure.
}
}
}
من تطبيق العميل، أرسِل الردّ من واجهة DigitalCredential API إلى خادم الخلفية حيث يمكن التحقّق منه واستخدامه للحصول على رقم الهاتف الذي تم التحقّق منه من خلال خدمة تجميع.
التحقّق من صحة استجابة "المستند الرقمي"
في ما يلي مثال على كيفية تحليل الردّ وتنفيذ خطوة التحقّق في الخلفية الخاصة بتطبيقك:
def processDigitalCredentialsResponse(response):
# Step 1: Parse out the TS.43 Digital Credential from the response
openId4VpResponse = response['data']
ts43_digital_credential = response['vp_token']["aggregator1"][0]
# Step 2: Perform response validation
verifyResponse(ts43_digital_credential)
def verifyResponse(ts43_digital_credential):
# The returned ts43_digital_credential is an SD-JWT-based Verifiable Credentials
# (SD-JWT VC) as defined in this IETF spec. The section 3.4 of the specification
# outlines how to validate the credential. At a high level, the steps involves
# validating (1) the nonce in the response credential matches the one in the
# request, (2) the integrity of the credential by checking the credential is
# signed by the trusted issuer Android Telephony, and (3) other validity
# properties associated with this credential, such as issue time and expiration
# time
# In most cases, you can use an SD-JWT VC library to perform these validations.
# Some aggregators may also perform the validation logic for you. Check with your
# aggregator to decide the exact scope of the validation required.
استبدال رقم الهاتف
من الخلفية في تطبيقك، أرسِل TS.43 Digital Credential الذي تم التحقّق منه إلى نقطة نهاية خدمة التجميع، وذلك للتحقّق من صحة بيانات الاعتماد وتلقّي رقم الهاتف الذي تم التحقّق منه.
def processDigitalCredentialsResponse(response):
# ... prior steps
# Step 3: Call aggregator endpoint to exchange the verified phone number
callAggregatorPnvEndpoint(ts43_digital_credential)