تطبيقات الويب التقدمية
واجهات الدفع وبيانات الاعتماد
واجهات الدفع وبيانات الاعتماد
يمكن لتطبيقات الويب الحديثة معالجة المدفوعات والمصادقة بشكل آمن باستخدام واجهات المتصفح الأصلية. يغطي هذا الدرس واجهة طلب الدفع لمعالجة المدفوعات وواجهة إدارة بيانات الاعتماد للمصادقة الآمنة.
واجهة طلب الدفع (Payment Request API)
توفر واجهة طلب الدفع تجربة دفع متسقة وأصلية للمتصفح تعمل عبر الأنظمة الأساسية وطرق الدفع.
<!-- طلب الدفع الأساسي -->
<button id="buyButton">اشتر الآن - $29.99</button>
<script>
const buyButton = document.getElementById('buyButton');
// التحقق من دعم طلب الدفع
if (window.PaymentRequest) {
buyButton.addEventListener('click', async () => {
// تحديد طرق الدفع
const supportedPaymentMethods = [
{
supportedMethods: 'basic-card',
data: {
supportedNetworks: ['visa', 'mastercard', 'amex'],
supportedTypes: ['debit', 'credit']
}
}
];
// تحديد تفاصيل الدفع
const paymentDetails = {
total: {
label: 'المبلغ الإجمالي',
amount: { currency: 'USD', value: '29.99' }
},
displayItems: [
{
label: 'دورة PWA',
amount: { currency: 'USD', value: '24.99' }
},
{
label: 'الضريبة',
amount: { currency: 'USD', value: '5.00' }
}
]
};
// اختياري: طلب معلومات الشحن
const options = {
requestPayerName: true,
requestPayerEmail: true,
requestPayerPhone: true,
requestShipping: false
};
try {
// إنشاء طلب الدفع
const request = new PaymentRequest(
supportedPaymentMethods,
paymentDetails,
options
);
// عرض واجهة الدفع
const paymentResponse = await request.show();
// معالجة الدفع
const result = await processPayment(paymentResponse);
if (result.success) {
await paymentResponse.complete('success');
console.log('تمت عملية الدفع بنجاح!');
} else {
await paymentResponse.complete('fail');
console.error('فشلت عملية الدفع');
}
} catch (error) {
console.error('خطأ في الدفع:', error);
}
});
} else {
// بديل للمتصفحات التي لا تدعم واجهة طلب الدفع
buyButton.addEventListener('click', () => {
window.location.href = '/checkout';
});
}
// محاكاة معالجة الدفع
async function processPayment(paymentResponse) {
const paymentData = {
methodName: paymentResponse.methodName,
details: paymentResponse.details,
payerName: paymentResponse.payerName,
payerEmail: paymentResponse.payerEmail
};
// إرسال إلى الخادم للمعالجة
const response = await fetch('/api/process-payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(paymentData)
});
return await response.json();
}
</script>
ملاحظة: يجب تشغيل واجهة طلب الدفع من خلال تفاعل المستخدم (نقرة زر) وتتطلب HTTPS في الإنتاج. لا تقم أبدًا بتخزين تفاصيل البطاقة في تطبيقك.
تكامل Google Pay
دمج Google Pay لتجربة دفع مبسطة على Android والويب.
<script>
// تكوين Google Pay
const googlePayConfig = {
apiVersion: 2,
apiVersionMinor: 0,
allowedPaymentMethods: [
{
type: 'CARD',
parameters: {
allowedAuthMethods: ['PAN_ONLY', 'CRYPTOGRAM_3DS'],
allowedCardNetworks: ['MASTERCARD', 'VISA']
},
tokenizationSpecification: {
type: 'PAYMENT_GATEWAY',
parameters: {
gateway: 'example',
gatewayMerchantId: 'exampleGatewayMerchantId'
}
}
}
],
merchantInfo: {
merchantId: 'BCR2DN4TR6G2RXXX',
merchantName: 'اسم متجرك'
},
transactionInfo: {
totalPriceStatus: 'FINAL',
totalPrice: '29.99',
currencyCode: 'USD',
countryCode: 'US'
}
};
// تهيئة Google Pay
async function initGooglePay() {
if (window.PaymentRequest) {
const supportedPaymentMethods = [
{
supportedMethods: 'https://google.com/pay',
data: googlePayConfig
}
];
const paymentDetails = {
total: {
label: 'الإجمالي',
amount: { currency: 'USD', value: '29.99' }
}
};
const request = new PaymentRequest(
supportedPaymentMethods,
paymentDetails
);
// التحقق من توفر Google Pay
const canMakePayment = await request.canMakePayment();
if (canMakePayment) {
document.getElementById('googlePayButton').style.display = 'block';
}
}
}
// معالجة دفع Google Pay
async function onGooglePayButtonClick() {
const request = new PaymentRequest(
[{ supportedMethods: 'https://google.com/pay', data: googlePayConfig }],
{ total: { label: 'الإجمالي', amount: { currency: 'USD', value: '29.99' } } }
);
try {
const paymentResponse = await request.show();
const paymentToken = paymentResponse.details.paymentMethodData.tokenizationData.token;
// إرسال الرمز إلى الخادم
const result = await fetch('/api/process-google-pay', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: paymentToken })
});
if (result.ok) {
await paymentResponse.complete('success');
} else {
await paymentResponse.complete('fail');
}
} catch (error) {
console.error('خطأ في Google Pay:', error);
}
}
initGooglePay();
</script>
تكامل Apple Pay
تمكين Apple Pay لمستخدمي iOS وmacOS Safari.
<script>
// التحقق من توفر Apple Pay
if (window.ApplePaySession && ApplePaySession.canMakePayments()) {
document.getElementById('applePayButton').style.display = 'block';
document.getElementById('applePayButton').addEventListener('click', () => {
// طلب دفع Apple Pay
const request = {
countryCode: 'US',
currencyCode: 'USD',
supportedNetworks: ['visa', 'masterCard', 'amex'],
merchantCapabilities: ['supports3DS'],
total: {
label: 'اسم متجرك',
amount: '29.99'
}
};
// إنشاء جلسة Apple Pay
const session = new ApplePaySession(3, request);
// التحقق من صحة التاجر
session.onvalidatemerchant = async (event) => {
const merchantSession = await fetch('/api/apple-pay-session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ validationURL: event.validationURL })
}).then(r => r.json());
session.completeMerchantValidation(merchantSession);
};
// معالجة تفويض الدفع
session.onpaymentauthorized = async (event) => {
const payment = event.payment;
// معالجة الدفع على الخادم
const result = await fetch('/api/process-apple-pay', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: payment.token })
}).then(r => r.json());
if (result.success) {
session.completePayment(ApplePaySession.STATUS_SUCCESS);
} else {
session.completePayment(ApplePaySession.STATUS_FAILURE);
}
};
session.begin();
});
}
</script>
تحذير: يتطلب Apple Pay التحقق من النطاق وشهادات التاجر. يجب معالجة رموز الدفع على الخادم الخاص بك، وليس من جانب العميل أبدًا. استخدم دائمًا HTTPS.
واجهة إدارة بيانات الاعتماد (Credential Management API)
تبسيط مصادقة المستخدم باستخدام بيانات الاعتماد المُدارة بواسطة المتصفح، بما في ذلك كلمات المرور وتسجيلات الدخول الموحدة.
<!-- نموذج تسجيل الدخول مع إدارة بيانات الاعتماد -->
<form id="loginForm">
<input type="email" id="email" name="email" autocomplete="username">
<input type="password" id="password" name="password" autocomplete="current-password">
<button type="submit">تسجيل الدخول</button>
</form>
<script>
// التحقق من دعم إدارة بيانات الاعتماد
if (window.PasswordCredential || window.FederatedCredential) {
// تسجيل دخول تلقائي ببيانات الاعتماد المخزنة
navigator.credentials.get({
password: true,
federated: {
providers: [
'https://accounts.google.com',
'https://www.facebook.com'
]
},
mediation: 'optional' // 'silent', 'optional', or 'required'
}).then(credential => {
if (credential) {
if (credential.type === 'password') {
// استخدام بيانات اعتماد كلمة المرور
return signInWithPassword(credential);
} else if (credential.type === 'federated') {
// استخدام بيانات الاعتماد الموحدة
return signInWithFederated(credential);
}
}
});
// تخزين بيانات الاعتماد بعد تسجيل الدخول الناجح
document.getElementById('loginForm').addEventListener('submit', async (e) => {
e.preventDefault();
const email = document.getElementById('email').value;
const password = document.getElementById('password').value;
// مصادقة المستخدم
const response = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
});
if (response.ok) {
// تخزين بيانات الاعتماد
const credential = new PasswordCredential({
id: email,
password: password,
name: 'اسم المستخدم',
iconURL: 'https://example.com/avatar.jpg'
});
await navigator.credentials.store(credential);
console.log('تم تخزين بيانات الاعتماد');
}
});
}
async function signInWithPassword(credential) {
const response = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: credential.id,
password: credential.password
})
});
if (response.ok) {
console.log('تم تسجيل الدخول بنجاح');
}
}
</script>
WebAuthn (واجهة مصادقة الويب)
تنفيذ المصادقة بدون كلمة مرور باستخدام القياسات الحيوية أو مفاتيح الأمان أو بيانات اعتماد الجهاز.
<button id="registerButton">التسجيل بالقياسات الحيوية</button>
<button id="authenticateButton">تسجيل الدخول بالقياسات الحيوية</button>
<script>
// تسجيل بيانات اعتماد جديدة (مثل بصمة الإصبع، التعرف على الوجه)
document.getElementById('registerButton').addEventListener('click', async () => {
try {
// الحصول على التحدي من الخادم
const challengeResponse = await fetch('/api/webauthn/register-challenge');
const options = await challengeResponse.json();
// إنشاء بيانات الاعتماد
const credential = await navigator.credentials.create({
publicKey: {
challenge: Uint8Array.from(options.challenge, c => c.charCodeAt(0)),
rp: {
name: 'اسم تطبيقك',
id: 'example.com'
},
user: {
id: Uint8Array.from(options.userId, c => c.charCodeAt(0)),
name: 'user@example.com',
displayName: 'اسم المستخدم'
},
pubKeyCredParams: [
{ alg: -7, type: 'public-key' }, // ES256
{ alg: -257, type: 'public-key' } // RS256
],
authenticatorSelection: {
authenticatorAttachment: 'platform', // 'platform' or 'cross-platform'
userVerification: 'required'
},
timeout: 60000
}
});
// إرسال بيانات الاعتماد إلى الخادم
await fetch('/api/webauthn/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: credential.id,
rawId: Array.from(new Uint8Array(credential.rawId)),
response: {
clientDataJSON: Array.from(new Uint8Array(credential.response.clientDataJSON)),
attestationObject: Array.from(new Uint8Array(credential.response.attestationObject))
}
})
});
console.log('تم التسجيل بالقياسات الحيوية بنجاح');
} catch (error) {
console.error('فشل التسجيل:', error);
}
});
// المصادقة ببيانات الاعتماد الموجودة
document.getElementById('authenticateButton').addEventListener('click', async () => {
try {
// الحصول على التحدي من الخادم
const challengeResponse = await fetch('/api/webauthn/login-challenge');
const options = await challengeResponse.json();
// الحصول على بيانات الاعتماد
const assertion = await navigator.credentials.get({
publicKey: {
challenge: Uint8Array.from(options.challenge, c => c.charCodeAt(0)),
rpId: 'example.com',
userVerification: 'required',
timeout: 60000
}
});
// إرسال التأكيد إلى الخادم
const response = await fetch('/api/webauthn/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: assertion.id,
rawId: Array.from(new Uint8Array(assertion.rawId)),
response: {
clientDataJSON: Array.from(new Uint8Array(assertion.response.clientDataJSON)),
authenticatorData: Array.from(new Uint8Array(assertion.response.authenticatorData)),
signature: Array.from(new Uint8Array(assertion.response.signature))
}
})
});
if (response.ok) {
console.log('تمت المصادقة بنجاح');
}
} catch (error) {
console.error('فشلت المصادقة:', error);
}
});
</script>
نصيحة: يوفر WebAuthn أعلى مستوى من الأمان للمصادقة. إنه مقاوم للتصيد الاحتيالي ويزيل نقاط الضعف في كلمات المرور. نفذه دائمًا مع التحقق من جانب الخادم.
تمرين:
- نفذ تدفق دفع أساسي لواجهة طلب الدفع مع خيارات دفع متعددة
- دمج Google Pay أو Apple Pay في PWA الخاص بك (اختر بناءً على النظام الأساسي المستهدف)
- أنشئ نموذج تسجيل دخول يخزن بيانات الاعتماد باستخدام واجهة إدارة بيانات الاعتماد
- نفذ المصادقة بدون كلمة مرور باستخدام WebAuthn مع القياسات الحيوية للجهاز
- قم ببناء تجربة دفع كاملة مع تسعير ديناميكي ومعالجة الدفع
أفضل ممارسات الأمان
- HTTPS مطلوب: تتطلب جميع واجهات الدفع وبيانات الاعتماد سياقات آمنة
- التحقق من الخادم: قم دائمًا بالتحقق من صحة المدفوعات ومعالجتها على الخادم، وليس من جانب العميل أبدًا
- معالجة الرموز: لا تقم أبدًا بتخزين رموز الدفع في localStorage أو ملفات تعريف الارتباط
- الامتثال لـ PCI: اتبع معايير PCI DSS عند التعامل مع بيانات البطاقة
- رسائل الخطأ: تجنب الكشف عن معلومات حساسة في رسائل الخطأ
- تحديد المعدل: نفذ تحديد المعدل على نقاط نهاية المصادقة
- سجلات التدقيق: سجل جميع محاولات الدفع والمصادقة لمراقبة الأمان