صفحه شروع به کار با Firebase Phone Number Verification جزئیات نحوه ادغام
با Firebase PNV را بااستفاده از روش getVerifiedPhoneNumber() شرح میدهد که
کل جریان Firebase PNV را مدیریت میکند، از کسب رضایت کاربر تا برقراری
تماسهای شبکه لازم با پسبخش Firebase PNV.
میانای برنامهسازی کاربردی تکروشی (getVerifiedPhoneNumber()) برای اکثر توسعهدهندگان توصیه میشود. بااینحال، اگر به کنترل دقیقتری بر تعامل با «مدیر اطلاعات کاربری Android» نیاز دارید (برای مثال، برای درخواست اطلاعات کاربری دیگر همراه با شماره تلفن)، کتابخانه Firebase PNV دو روش زیر را نیز ارائه میدهد که هرکدام تعامل متفاوتی را با پسبک Firebase PNV مدیریت میکنند:
getDigitalCredentialPayload()درخواست امضاشده توسط سرور را دریافت میکند که از آن برای فراخوانی «مدیر اطلاعات کاربری» استفاده خواهید کرد.exchangeCredentialResponseForPhoneNumber()پاسخ Credential Manager را با یک توکن امضاشده حاوی شماره تلفن تأییدشده مبادله میکند. صدور صورتحساب در این مرحله انجام میشود.
بین فراخوانی هرکدام از این روشها، شما مسئول مدیریت تعامل با Credential Manager API در Android هستید. این صفحه نمای کلیای از نحوه پیادهسازی این جریان سهبخشی ارائه میدهد.
قبل از شروع
پروژه Firebase خود را راهاندازی کنید و وابستگیهای Firebase PNV را همانطور که در صفحه شروع به کار توضیح داده شده است وارد کنید.
۱. دریافت بار داده درخواست «اعتبارنامه دیجیتال»
روش getDigitalCredentialPayload() را برای ایجاد درخواست شماره تلفن دستگاه فراخوانی کنید. در مرحله بعد، این درخواست بار مفید
تعامل شما با Credential Manager API خواهد بود.
Kotlin
// This instance does not require an Activity context.
val fpnv = FirebasePhoneNumberVerification.getInstance()
// Your request should include a nonce, which will propagate through the flow
// and be present in the final response from FPNV. See the section "Verifying
// the Firebase PNV token" for details on generating and verifying this.
val nonce = fetchNonceFromYourServer()
fpnv.getDigitalCredentialPayload(nonce)
.addOnSuccessListener { fpnvDigitalCredentialPayload ->
// Use the payload in the next step.
// ...
}
.addOnFailureListener { e -> /* Handle payload fetch failure */ }
۲. ایجاد درخواست اطلاعات اعتباری دیجیتال بااستفاده از «مدیر اطلاعات اعتباری»
سپس، درخواست را به Credential Manager ارسال کنید.
برای انجام این کار، باید بار داده درخواست را در درخواست DigitalCredential API
بپیچید. این درخواست باید شامل همان نانسی باشد که به
getDigitalCredentialPayload() ارسال کردید.
Kotlin
// This example uses string interpolation for clarity, but you should use some kind of type-safe
// serialization method.
fun buildDigitalCredentialRequestJson(nonce: String, fpnvDigitalCredentialPayload: String) = """
{
"requests": [
{
"protocol": "openid4vp-v1-unsigned",
"data": {
"response_type": "vp_token",
"response_mode": "dc_api",
"nonce": "$nonce",
"dcql_query": { "credentials": [$fpnvDigitalCredentialPayload] }
}
}
]
}
""".trimIndent()
پساز انجام این کار، میتوانید بااستفاده از Credential Manager API درخواست را ارسال کنید:
Kotlin
suspend fun makeFpnvRequest(
context: Activity, nonce: String, fpnvDigitalCredentialPayload: String): GetCredentialResponse {
// Helper function to build the digital credential request (defined above).
// Pass the same nonce you passed to getDigitalCredentialPayload().
val digitalCredentialRequestJson =
buildDigitalCredentialRequestJson(nonce, fpnvDigitalCredentialPayload)
// CredentialManager requires an Activity context.
val credentialManager = CredentialManager.create(context)
// Build a Credential Manager request that includes the Firebase PNV option. Note that
// you can't combine the digital credential option with other options.
val request = GetCredentialRequest.Builder()
.addCredentialOption(GetDigitalCredentialOption(digitalCredentialRequestJson))
.build()
// getCredential is a suspend function, so it must run in a coroutine scope,
val cmResponse: GetCredentialResponse = try {
credentialManager.getCredential(context, request)
} catch (e: GetCredentialException) {
// If the 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.
throw e
}
return cmResponse
}
اگر فراخوانی Credential Manager موفقیتآمیز باشد، پاسخ آن حاوی یک اعتبارنامه دیجیتال خواهد بود که میتوانید آن را بااستفاده از کدی مانند مثال زیر استخراج کنید:
Kotlin
val dcApiResponse = extractApiResponse(cmResponse)
fun extractApiResponse(response: GetCredentialResponse): String {
val credential = response.credential
when (credential) {
is DigitalCredential -> {
val json = JSONObject(credential.credentialJson)
val firebaseJwtArray =
json.getJSONObject("data").getJSONObject("vp_token").getJSONArray("firebase")
return firebaseJwtArray.getString(0)
}
else -> {
// Handle any unrecognized credential type here.
Log.e(TAG, "Unexpected type of credential ${credential.type}")
}
}
}
۳. مبادله پاسخ اطلاعات اعتباری دیجیتال با یک کد Firebase PNV
درنهایت، روش exchangeCredentialResponseForPhoneNumber() را فراخوانی کنید تا
پاسخ اطلاعات کاربری دیجیتال را با شماره تلفن تأییدشده و یک
Firebase PNV توکن مبادله کنید:
Kotlin
fpnv.exchangeCredentialResponseForPhoneNumber(dcApiResponse)
.addOnSuccessListener { result ->
val phoneNumber = result.getPhoneNumber()
// Verification successful
}
.addOnFailureListener { e -> /* Handle exchange failure */ }
وقتی این مرحله با موفقیت تکمیل شود و شماره تلفن درستیسنجیشده به برنامهتان برگردانده شود، صدور صورتحساب را راهاندازی میکند.
۴. درحال درستیسنجی کد Firebase PNV
اگر جریان موفقیتآمیز باشد، روش getVerifiedPhoneNumber() شماره تلفن درستیسنجیشده و یک کد امضاشده حاوی آن را برمیگرداند. میتوانید از این دادهها در برنامهتان
طبق آنچه در خطمشی رازداریتان مستند شده است استفاده کنید.
اگر از شماره تلفن درستیسنجیشده در خارج از کارخواه برنامه استفاده میکنید، باید بهجای خود شماره تلفن، کد را ارسال کنید تا بتوانید هنگام استفاده از آن، یکپارچگی آن را درستیسنجی کنید. برای درستیسنجی کردن توکنها، باید دو نقطه پایانی را پیادهسازی کنید:
- نقطه پایانی تولید نانس
- نقطه پایانی درستیسنجی کد
پیادهسازی این نقاط پایانی به شما بستگی دارد؛ مثالهای زیر نشان میدهند چگونه میتوانید آنها را بااستفاده از Node.js و Express پیادهسازی کنید.
درحال تولید نانس
این نقطه پایانی مسئول تولید و ذخیره موقت مقادیر تکبار مصرفی به نام «نانس» است که برای جلوگیری از حملات تکراری علیه نقاط پایانی شما استفاده میشود. بهعنوان مثال، ممکن است یک مسیر Express به این صورت تعریف شده باشد:
Node.js
app.get('/fpnvNonce', async (req, res) => {
const nonce = crypto.randomUUID();
// TODO: Save the nonce to a database, key store, etc.
// You should also assign the nonce an expiration time and periodically
// clear expired nonces from your database.
await persistNonce({
nonce,
expiresAt: Date.now() + 180000, // Give it a short duration.
});
// Return the nonce to the caller.
res.send({ nonce });
});
این نقطه پایانی است که تابع جایبان،
fetchNonceFromYourServer()، در مرحله ۱ فراخوانی میکند. این عدد یکبارمصرف ازطریق تماسهای مختلف شبکهای که کارخواه انجام میدهد منتشر میشود و درنهایت در کد Firebase PNV به سرور شما برمیگردد. در مرحله بعدی، درستیسنجی میکنید
که توکن حاوی یک عدد یکباراستفاده است که شما تولید کردهاید.
درحال درستیسنجی کدها
این نقطه پایانی، Firebase PNV کد از مشتری شما دریافت میکند و اصالت آنها را درستیسنجی میکند. برای درستیسنجی کردن یک توکن، باید موارد زیر را بررسی کنید:
سرایند
typرویJWTتنظیم شده است.این کد بااستفاده از یکی از کلیدهای منتشرشده در نقطه پایانی Firebase PNV JWKS با الگوریتم
ES256امضا میشود:https://fpnv.googleapis.com/v1beta/jwksادعاهای صادرکننده حاوی شماره پروژه Firebase شما است و در قالب زیر است:
https://fpnv.googleapis.com/projects/FIREBASE_PROJECT_NUMBERمیتوانید شماره پروژه Firebase خود را در
تنظیمات > برگه عمومی کنسول Firebase پیدا کنید.ادعای مخاطب فهرستی است که حاوی شماره پروژه Firebase و شناسه پروژه شما است و در قالب زیر است:
[ https://fpnv.googleapis.com/projects/FIREBASE_PROJECT_NUMBER, https://fpnv.googleapis.com/projects/FIREBASE_PROJECT_ID, ]کد منقضی نشده است.
توکن حاوی یک عدد یکبارمصرف معتبر است. یک نانس معتبر است اگر:
- آن را تولید کردهاید (یعنی در هر سازوکار پایداری که استفاده میکنید، قابل یافتن است)
- قبلاً استفاده نشده باشد
- منقضی نشده است
برای مثال، پیادهسازی Express ممکن است چیزی شبیه به این باشد:
Node.js
import { JwtVerifier } from "aws-jwt-verify";
// Find your Firebase project number in the Firebase console.
const FIREBASE_PROJECT_NUMBER = "123456789";
// The issuer and audience claims of the FPNV token are specific to your
// project.
const issuer = `https://fpnv.googleapis.com/projects/${FIREBASE_PROJECT_NUMBER}`;
const audience = `https://fpnv.googleapis.com/projects/${FIREBASE_PROJECT_NUMBER}`;
// The JWKS URL contains the current public signing keys for FPNV tokens.
const jwksUri = "https://fpnv.googleapis.com/v1beta/jwks";
// Configure a JWT verifier to check the following:
// - The token is signed by Google
// - The issuer and audience claims match your project
// - The token has not yet expired (default begavior)
const fpnvVerifier = JwtVerifier.create({ issuer, audience, jwksUri });
app.post('/verifiedPhoneNumber', async (req, res) => {
if (!req.body) return res.sendStatus(400);
// Get the token from the body of the request.
const fpnvToken = req.body;
try {
// Attempt to verify the token using the verifier configured above.
const verifiedPayload = await fpnvVerifier.verify(fpnvToken);
// Now that you've verified the signature and claims, verify the nonce.
// TODO: Try to look up the nonce in your database and remove it if it's
// found; if it's not found or it's expired, throw an error.
await testAndRemoveNonce(verifiedPayload.nonce);
// Only after verifying the JWT signature, claims, and nonce, get the
// verified phone number from the subject claim.
// You can use this value however it's needed by your app.
const verifiedPhoneNumber = verifiedPayload.sub;
// (Do something with it...)
return res.sendStatus(200);
} catch {
// If verification fails, reject the token.
return res.sendStatus(400);
}
});