Google is committed to advancing racial equity for Black communities. See how.
ترجمت واجهة Cloud Translation API‏ هذه الصفحة.
Switch to English

إدارة جلسات المستخدم

تدوم جلسات مصادقة Firebase لفترة طويلة. في كل مرة يسجل فيها المستخدم الدخول ، يتم إرسال بيانات اعتماد المستخدم إلى الواجهة الخلفية لمصادقة Firebase ويتم استبدالها برمز مميز لمعرف Firebase (JWT) ورمز التحديث المميز. الرموز المميزة لـ Firebase ID قصيرة العمر وتستمر لمدة ساعة ؛ يمكن استخدام رمز التحديث لاسترداد الرموز المميزة الجديدة للمعرف. تنتهي صلاحية الرموز المميزة للتحديث فقط عند حدوث أي مما يلي:

  • تم حذف المستخدم
  • المستخدم معطل
  • تم الكشف عن تغيير حساب كبير للمستخدم. يتضمن هذا أحداثًا مثل تحديثات كلمة المرور أو عنوان البريد الإلكتروني.

توفر حزمة Firebase Admin SDK القدرة على إبطال الرموز المميزة للتحديث لمستخدم محدد. بالإضافة إلى ذلك ، تتوفر أيضًا واجهة برمجة تطبيقات للتحقق من إبطال رمز المعرف. مع هذه القدرات ، يمكنك التحكم بشكل أكبر في جلسات المستخدم. توفر SDK القدرة على إضافة قيود لمنع استخدام الجلسات في ظروف مشبوهة ، بالإضافة إلى آلية للاسترداد من سرقة الرمز المميز المحتملة.

إبطال رموز التحديث

يمكنك إبطال رمز التحديث المميز الحالي للمستخدم عندما يبلغ المستخدم عن جهاز مفقود أو مسروق. وبالمثل ، إذا اكتشفت ثغرة أمنية عامة أو اشتبهت في تسرب واسع النطاق للرموز النشطة ، فيمكنك استخدام listUsers API للبحث عن جميع المستخدمين وإلغاء الرموز الخاصة بهم للمشروع المحدد.

تؤدي عمليات إعادة تعيين كلمة المرور أيضًا إلى إبطال الرموز المميزة الموجودة للمستخدم ؛ ومع ذلك ، فإن الواجهة الخلفية لمصادقة Firebase تعالج الإبطال تلقائيًا في هذه الحالة. عند الإلغاء ، يتم تسجيل خروج المستخدم ويطلب منه إعادة المصادقة.

فيما يلي مثال على التنفيذ الذي يستخدم Admin SDK لإبطال رمز التحديث المميز لمستخدم معين. لتهيئة Admin SDK ، اتبع الإرشادات الموجودة على صفحة الإعداد .

Node.js

// Revoke all refresh tokens for a specified user for whatever reason.
// Retrieve the timestamp of the revocation, in seconds since the epoch.
admin.auth().revokeRefreshTokens(uid)
  .then(() => {
    return admin.auth().getUser(uid);
  })
  .then((userRecord) => {
    return new Date(userRecord.tokensValidAfterTime).getTime() / 1000;
  })
  .then((timestamp) => {
    console.log('Tokens revoked at: ', timestamp);
  });

جافا

FirebaseAuth.getInstance().revokeRefreshTokens(uid);
UserRecord user = FirebaseAuth.getInstance().getUser(uid);
// Convert to seconds as the auth_time in the token claims is in seconds too.
long revocationSecond = user.getTokensValidAfterTimestamp() / 1000;
System.out.println("Tokens revoked at: " + revocationSecond);

بايثون

# Revoke tokens on the backend.
auth.revoke_refresh_tokens(uid)
user = auth.get_user(uid)
# Convert to seconds as the auth_time in the token claims is in seconds.
revocation_second = user.tokens_valid_after_timestamp / 1000
print('Tokens revoked at: {0}'.format(revocation_second))

اذهب

client, err := app.Auth(ctx)
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}
if err := client.RevokeRefreshTokens(ctx, uid); err != nil {
	log.Fatalf("error revoking tokens for user: %v, %v\n", uid, err)
}
// accessing the user's TokenValidAfter
u, err := client.GetUser(ctx, uid)
if err != nil {
	log.Fatalf("error getting user %s: %v\n", uid, err)
}
timestamp := u.TokensValidAfterMillis / 1000
log.Printf("the refresh tokens were revoked at: %d (UTC seconds) ", timestamp)

سي #

await FirebaseAuth.DefaultInstance.RevokeRefreshTokensAsync(uid);
var user = await FirebaseAuth.DefaultInstance.GetUserAsync(uid);
Console.WriteLine("Tokens revoked at: " + user.TokensValidAfterTimestamp);

كشف هوية إبطال الرمز المميز

نظرًا لأن الرموز المميزة لمعرف Firebase هي JWTs عديمة الحالة ، يمكنك تحديد أنه تم إبطال رمز مميز فقط من خلال طلب حالة الرمز المميز من الواجهة الخلفية لمصادقة Firebase. لهذا السبب ، يعد إجراء هذا الفحص على الخادم الخاص بك عملية مكلفة تتطلب رحلة ذهاب وعودة إضافية للشبكة. يمكنك تجنب إجراء طلب الشبكة هذا عن طريق إعداد قواعد Firebase التي تتحقق من الإبطال بدلاً من استخدام Admin SDK لإجراء الفحص.

كشف إبطال الرمز المميز في قواعد قاعدة البيانات

لتتمكن من اكتشاف إبطال الرمز المميز للمعرف باستخدام قواعد قاعدة البيانات ، يجب علينا أولاً تخزين بعض البيانات الوصفية الخاصة بالمستخدم.

تحديث البيانات الوصفية الخاصة بالمستخدم في قاعدة بيانات Firebase Realtime.

احفظ الطابع الزمني لإبطال الرمز المميز للتحديث. هذا ضروري لتتبع إبطال الرمز المميز للمعرف عبر قواعد Firebase. هذا يسمح بإجراء فحوصات فعالة داخل قاعدة البيانات في نماذج الكود أدناه ، استخدم uid ووقت الإلغاء الذي تم الحصول عليه في القسم السابق .

Node.js

const metadataRef = admin.database().ref('metadata/' + uid);
metadataRef.set({revokeTime: utcRevocationTimeSecs})
  .then(() => {
    console.log('Database updated successfully.');
  });

جافا

DatabaseReference ref = FirebaseDatabase.getInstance().getReference("metadata/" + uid);
Map<String, Object> userData = new HashMap<>();
userData.put("revokeTime", revocationSecond);
ref.setValueAsync(userData);

بايثون

metadata_ref = firebase_admin.db.reference("metadata/" + uid)
metadata_ref.set({'revokeTime': revocation_second})

قم بإضافة تحقق إلى قواعد قاعدة البيانات

لفرض هذا الفحص ، قم بإعداد قاعدة بدون وصول للكتابة للعميل لتخزين وقت الإبطال لكل مستخدم. يمكن تحديث هذا بالطابع الزمني UTC لوقت الإلغاء الأخير كما هو موضح في الأمثلة السابقة:

{
  "rules": {
    "metadata": {
      "$user_id": {
        // this could be false as it is only accessed from backend or rules.
        ".read": "$user_id === auth.uid",
        ".write": "false",
      }
    }
  }
}

يجب تكوين القاعدة التالية لأي بيانات تتطلب وصولاً مصدقًا. يسمح هذا المنطق فقط للمستخدمين المصادق عليهم مع رموز معرف غير ملغاة بالوصول إلى البيانات المحمية:

{
  "rules": {
    "users": {
      "$user_id": {
        ".read": "$user_id === auth.uid && auth.token.auth_time > (root.child('metadata').child(auth.uid).child('revokeTime').val() || 0)",
        ".write": "$user_id === auth.uid && auth.token.auth_time > (root.child('metadata').child(auth.uid).child('revokeTime').val() || 0)"
      }
    }
  }
}

كشف إبطال الرمز المميز للمعرف في SDK.

في الخادم الخاص بك ، قم بتنفيذ المنطق التالي لإبطال رمز التحديث والتحقق من صحة الرمز المميز للمعرف:

عندما يتم التحقق من رمز معرف المستخدم ، يجب تمرير علامة checkRevoked المنطقية الإضافية checkRevoked verifyIdToken . إذا تم إبطال الرمز المميز للمستخدم ، فيجب تسجيل خروج المستخدم من العميل أو مطالبتك بإعادة المصادقة باستخدام واجهات برمجة تطبيقات إعادة المصادقة التي توفرها حزم SDK لعميل مصادقة Firebase.

لتهيئة Admin SDK للنظام الأساسي الخاص بك ، اتبع الإرشادات الموجودة على صفحة الإعداد . توجد أمثلة على استرداد الرمز المميز verifyIdToken قسم verifyIdToken من verifyIdToken .

Node.js

// Verify the ID token while checking if the token is revoked by passing
// checkRevoked true.
let checkRevoked = true;
admin.auth().verifyIdToken(idToken, checkRevoked)
  .then(payload => {
    // Token is valid.
  })
  .catch(error => {
    if (error.code == 'auth/id-token-revoked') {
      // Token has been revoked. Inform the user to reauthenticate or signOut() the user.
    } else {
      // Token is invalid.
    }
  });

جافا

try {
  // Verify the ID token while checking if the token is revoked by passing checkRevoked
  // as true.
  boolean checkRevoked = true;
  FirebaseToken decodedToken = FirebaseAuth.getInstance()
      .verifyIdToken(idToken, checkRevoked);
  // Token is valid and not revoked.
  String uid = decodedToken.getUid();
} catch (FirebaseAuthException e) {
  if (e.getAuthErrorCode() == AuthErrorCode.REVOKED_ID_TOKEN) {
    // Token has been revoked. Inform the user to re-authenticate or signOut() the user.
  } else {
    // Token is invalid.
  }
}

بايثون

try:
    # Verify the ID token while checking if the token is revoked by
    # passing check_revoked=True.
    decoded_token = auth.verify_id_token(id_token, check_revoked=True)
    # Token is valid and not revoked.
    uid = decoded_token['uid']
except auth.RevokedIdTokenError:
    # Token revoked, inform the user to reauthenticate or signOut().
    pass
except auth.InvalidIdTokenError:
    # Token is invalid
    pass

اذهب

client, err := app.Auth(ctx)
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}
token, err := client.VerifyIDTokenAndCheckRevoked(ctx, idToken)
if err != nil {
	if err.Error() == "ID token has been revoked" {
		// Token is revoked. Inform the user to reauthenticate or signOut() the user.
	} else {
		// Token is invalid
	}
}
log.Printf("Verified ID token: %v\n", token)

سي #

try
{
    // Verify the ID token while checking if the token is revoked by passing checkRevoked
    // as true.
    bool checkRevoked = true;
    var decodedToken = await FirebaseAuth.DefaultInstance.VerifyIdTokenAsync(
        idToken, checkRevoked);
    // Token is valid and not revoked.
    string uid = decodedToken.Uid;
}
catch (FirebaseAuthException ex)
{
    if (ex.AuthErrorCode == AuthErrorCode.RevokedIdToken)
    {
        // Token has been revoked. Inform the user to re-authenticate or signOut() the user.
    }
    else
    {
        // Token is invalid.
    }
}

الرد على إبطال الرمز المميز على العميل

إذا تم إبطال الرمز المميز عبر Admin SDK ، فسيتم إبلاغ العميل بالإلغاء ويُتوقع من المستخدم إعادة المصادقة أو تسجيل الخروج:

function onIdTokenRevocation() {
  // For an email/password user. Prompt the user for the password again.
  let password = prompt('Please provide your password for reauthentication');
  let credential = firebase.auth.EmailAuthProvider.credential(
      firebase.auth().currentUser.email, password);
  firebase.auth().currentUser.reauthenticateWithCredential(credential)
    .then(result => {
      // User successfully reauthenticated. New ID tokens should be valid.
    })
    .catch(error => {
      // An error occurred.
    });
}

الأمان المتقدم: فرض قيود عنوان IP

تتمثل إحدى آليات الأمان الشائعة لاكتشاف سرقة الرمز المميز في تتبع أصول عنوان IP للطلب. على سبيل المثال ، إذا كانت الطلبات تأتي دائمًا من نفس عنوان IP (الخادم الذي يجري المكالمة) ، فيمكن فرض جلسات عنوان IP الفردية. أو يمكنك إبطال رمز المستخدم إذا اكتشفت أن عنوان IP الخاص بالمستخدم قد تغير فجأة الموقع الجغرافي أو تلقيت طلبًا من مصدر مشبوه.

لإجراء فحوصات الأمان استنادًا إلى عنوان IP ، قم بفحص الرمز المميز لكل طلب مصادق عليه وتحقق مما إذا كان عنوان IP الخاص بالطلب يطابق عناوين IP الموثوقة السابقة أم أنه ضمن نطاق موثوق قبل السماح بالوصول إلى البيانات المقيدة. فمثلا:

app.post('/getRestrictedData', (req, res) => {
  // Get the ID token passed.
  const idToken = req.body.idToken;
  // Verify the ID token, check if revoked and decode its payload.
  admin.auth().verifyIdToken(idToken, true).then((claims) => {
    // Get the user's previous IP addresses, previously saved.
    return getPreviousUserIpAddresses(claims.sub);
  }).then(previousIpAddresses => {
    // Get the request IP address.
    const requestIpAddress = req.connection.remoteAddress;
    // Check if the request IP address origin is suspicious relative to previous
    // IP addresses. The current request timestamp and the auth_time of the ID
    // token can provide additional signals of abuse especially if the IP address
    // suddenly changed. If there was a sudden location change in a
    // short period of time, then it will give stronger signals of possible abuse.
    if (!isValidIpAddress(previousIpAddresses, requestIpAddress)) {
      // Invalid IP address, take action quickly and revoke all user's refresh tokens.
      revokeUserTokens(claims.uid).then(() => {
        res.status(401).send({error: 'Unauthorized access. Please login again!'});
      }, error => {
        res.status(401).send({error: 'Unauthorized access. Please login again!'});
      });
    } else {
      // Access is valid. Try to return data.
      getData(claims).then(data => {
        res.end(JSON.stringify(data);
      }, error => {
        res.status(500).send({ error: 'Server error!' })
      });
    }
  });
});