Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

إدارة ملفات تعريف الارتباط للجلسة

تنظيم صفحاتك في مجموعات يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.

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

  • أمان محسّن عبر الرموز المميزة للجلسة المستندة إلى JWT والتي لا يمكن إنشاؤها إلا باستخدام حسابات الخدمة المصرح بها.
  • ملفات تعريف الارتباط للجلسة عديمة الحالة والتي تأتي مع كل مزايا استخدام JWTs للمصادقة. يحتوي ملف تعريف ارتباط الجلسة على نفس المطالبات (بما في ذلك المطالبات المخصصة) مثل رمز المعرف المميز ، مما يجعل عمليات التحقق من الأذونات نفسها قابلة للتنفيذ على ملفات تعريف ارتباط الجلسة.
  • القدرة على إنشاء ملفات تعريف الارتباط للجلسة بأوقات انتهاء مخصصة تتراوح من 5 دقائق إلى أسبوعين.
  • المرونة في فرض سياسات ملفات تعريف الارتباط بناءً على متطلبات التطبيق: المجال ، والمسار ، والآمن ، و httpOnly ، وما إلى ذلك.
  • القدرة على إبطال ملفات تعريف الارتباط للجلسة عند الاشتباه في سرقة الرمز المميز باستخدام واجهة برمجة التطبيقات الحالية لإبطال رمز التحديث.
  • القدرة على اكتشاف إبطال الجلسة على تغييرات الحساب الرئيسية.

تسجيل الدخول

بافتراض أن أحد التطبيقات يستخدم httpOnly ملفات تعريف الارتباط من جانب الخادم ، قم بتسجيل دخول مستخدم على صفحة تسجيل الدخول باستخدام أدوات تطوير البرامج (SDK) الخاصة بالعميل. يتم إنشاء رمز مميز لمعرف Firebase ، ثم يتم إرسال الرمز المميز للمعرف عبر HTTP POST إلى نقطة نهاية تسجيل الدخول للجلسة حيث يتم إنشاء ملف تعريف ارتباط للجلسة باستخدام Admin SDK. عند النجاح ، يجب تخليص الدولة من التخزين من جانب العميل.

firebase.initializeApp({
  apiKey: 'AIza…',
  authDomain: '<PROJECT_ID>.firebasepp.com'
});

// As httpOnly cookies are to be used, do not persist any state client side.
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.NONE);

// When the user signs in with email and password.
firebase.auth().signInWithEmailAndPassword('user@example.com', 'password').then(user => {
  // Get the user's ID token as it is needed to exchange for a session cookie.
  return user.getIdToken().then(idToken = > {
    // Session login endpoint is queried and the session cookie is set.
    // CSRF protection should be taken into account.
    // ...
    const csrfToken = getCookie('csrfToken')
    return postIdTokenToSessionLogin('/sessionLogin', idToken, csrfToken);
  });
}).then(() => {
  // A page redirect would suffice as the persistence is set to NONE.
  return firebase.auth().signOut();
}).then(() => {
  window.location.assign('/profile');
});

لإنشاء ملف تعريف ارتباط للجلسة مقابل رمز المعرف المميز المقدم ، يلزم وجود نقطة نهاية HTTP. أرسل الرمز المميز إلى نقطة النهاية ، وحدد مدة جلسة مخصصة باستخدام Firebase Admin SDK. يجب اتخاذ التدابير المناسبة لمنع هجمات طلبات التزوير عبر المواقع (CSRF).

Node.js

app.post('/sessionLogin', (req, res) => {
  // Get the ID token passed and the CSRF token.
  const idToken = req.body.idToken.toString();
  const csrfToken = req.body.csrfToken.toString();
  // Guard against CSRF attacks.
  if (csrfToken !== req.cookies.csrfToken) {
    res.status(401).send('UNAUTHORIZED REQUEST!');
    return;
  }
  // Set session expiration to 5 days.
  const expiresIn = 60 * 60 * 24 * 5 * 1000;
  // Create the session cookie. This will also verify the ID token in the process.
  // The session cookie will have the same claims as the ID token.
  // To only allow session cookie setting on recent sign-in, auth_time in ID token
  // can be checked to ensure user was recently signed in before creating a session cookie.
  getAuth()
    .createSessionCookie(idToken, { expiresIn })
    .then(
      (sessionCookie) => {
        // Set cookie policy for session cookie.
        const options = { maxAge: expiresIn, httpOnly: true, secure: true };
        res.cookie('session', sessionCookie, options);
        res.end(JSON.stringify({ status: 'success' }));
      },
      (error) => {
        res.status(401).send('UNAUTHORIZED REQUEST!');
      }
    );
});

جافا

@POST
@Path("/sessionLogin")
@Consumes("application/json")
public Response createSessionCookie(LoginRequest request) {
  // Get the ID token sent by the client
  String idToken = request.getIdToken();
  // Set session expiration to 5 days.
  long expiresIn = TimeUnit.DAYS.toMillis(5);
  SessionCookieOptions options = SessionCookieOptions.builder()
      .setExpiresIn(expiresIn)
      .build();
  try {
    // Create the session cookie. This will also verify the ID token in the process.
    // The session cookie will have the same claims as the ID token.
    String sessionCookie = FirebaseAuth.getInstance().createSessionCookie(idToken, options);
    // Set cookie policy parameters as required.
    NewCookie cookie = new NewCookie("session", sessionCookie /* ... other parameters */);
    return Response.ok().cookie(cookie).build();
  } catch (FirebaseAuthException e) {
    return Response.status(Status.UNAUTHORIZED).entity("Failed to create a session cookie")
        .build();
  }
}

بايثون

@app.route('/sessionLogin', methods=['POST'])
def session_login():
    # Get the ID token sent by the client
    id_token = flask.request.json['idToken']
    # Set session expiration to 5 days.
    expires_in = datetime.timedelta(days=5)
    try:
        # Create the session cookie. This will also verify the ID token in the process.
        # The session cookie will have the same claims as the ID token.
        session_cookie = auth.create_session_cookie(id_token, expires_in=expires_in)
        response = flask.jsonify({'status': 'success'})
        # Set cookie policy for session cookie.
        expires = datetime.datetime.now() + expires_in
        response.set_cookie(
            'session', session_cookie, expires=expires, httponly=True, secure=True)
        return response
    except exceptions.FirebaseError:
        return flask.abort(401, 'Failed to create a session cookie')

يذهب

return func(w http.ResponseWriter, r *http.Request) {
	// Get the ID token sent by the client
	defer r.Body.Close()
	idToken, err := getIDTokenFromBody(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	// Set session expiration to 5 days.
	expiresIn := time.Hour * 24 * 5

	// Create the session cookie. This will also verify the ID token in the process.
	// The session cookie will have the same claims as the ID token.
	// To only allow session cookie setting on recent sign-in, auth_time in ID token
	// can be checked to ensure user was recently signed in before creating a session cookie.
	cookie, err := client.SessionCookie(r.Context(), idToken, expiresIn)
	if err != nil {
		http.Error(w, "Failed to create a session cookie", http.StatusInternalServerError)
		return
	}

	// Set cookie policy for session cookie.
	http.SetCookie(w, &http.Cookie{
		Name:     "session",
		Value:    cookie,
		MaxAge:   int(expiresIn.Seconds()),
		HttpOnly: true,
		Secure:   true,
	})
	w.Write([]byte(`{"status": "success"}`))
}

سي #

// POST: /sessionLogin
[HttpPost]
public async Task<ActionResult> Login([FromBody] LoginRequest request)
{
    // Set session expiration to 5 days.
    var options = new SessionCookieOptions()
    {
        ExpiresIn = TimeSpan.FromDays(5),
    };

    try
    {
        // Create the session cookie. This will also verify the ID token in the process.
        // The session cookie will have the same claims as the ID token.
        var sessionCookie = await FirebaseAuth.DefaultInstance
            .CreateSessionCookieAsync(request.IdToken, options);

        // Set cookie policy parameters as required.
        var cookieOptions = new CookieOptions()
        {
            Expires = DateTimeOffset.UtcNow.Add(options.ExpiresIn),
            HttpOnly = true,
            Secure = true,
        };
        this.Response.Cookies.Append("session", sessionCookie, cookieOptions);
        return this.Ok();
    }
    catch (FirebaseAuthException)
    {
        return this.Unauthorized("Failed to create a session cookie");
    }
}

بالنسبة للتطبيقات الحساسة ، يجب التحقق من وقت auth_time قبل إصدار ملف تعريف ارتباط الجلسة ، مما يقلل نافذة الهجوم في حالة سرقة رمز معرف:

Node.js

getAuth()
  .verifyIdToken(idToken)
  .then((decodedIdToken) => {
    // Only process if the user just signed in in the last 5 minutes.
    if (new Date().getTime() / 1000 - decodedIdToken.auth_time < 5 * 60) {
      // Create session cookie and set it.
      return getAuth().createSessionCookie(idToken, { expiresIn });
    }
    // A user that was not recently signed in is trying to set a session cookie.
    // To guard against ID token theft, require re-authentication.
    res.status(401).send('Recent sign in required!');
  });

جافا

// To ensure that cookies are set only on recently signed in users, check auth_time in
// ID token before creating a cookie.
FirebaseToken decodedToken = FirebaseAuth.getInstance().verifyIdToken(idToken);
long authTimeMillis = TimeUnit.SECONDS.toMillis(
    (long) decodedToken.getClaims().get("auth_time"));

// Only process if the user signed in within the last 5 minutes.
if (System.currentTimeMillis() - authTimeMillis < TimeUnit.MINUTES.toMillis(5)) {
  long expiresIn = TimeUnit.DAYS.toMillis(5);
  SessionCookieOptions options = SessionCookieOptions.builder()
      .setExpiresIn(expiresIn)
      .build();
  String sessionCookie = FirebaseAuth.getInstance().createSessionCookie(idToken, options);
  // Set cookie policy parameters as required.
  NewCookie cookie = new NewCookie("session", sessionCookie);
  return Response.ok().cookie(cookie).build();
}
// User did not sign in recently. To guard against ID token theft, require
// re-authentication.
return Response.status(Status.UNAUTHORIZED).entity("Recent sign in required").build();

بايثون

# To ensure that cookies are set only on recently signed in users, check auth_time in
# ID token before creating a cookie.
try:
    decoded_claims = auth.verify_id_token(id_token)
    # Only process if the user signed in within the last 5 minutes.
    if time.time() - decoded_claims['auth_time'] < 5 * 60:
        expires_in = datetime.timedelta(days=5)
        expires = datetime.datetime.now() + expires_in
        session_cookie = auth.create_session_cookie(id_token, expires_in=expires_in)
        response = flask.jsonify({'status': 'success'})
        response.set_cookie(
            'session', session_cookie, expires=expires, httponly=True, secure=True)
        return response
    # User did not sign in recently. To guard against ID token theft, require
    # re-authentication.
    return flask.abort(401, 'Recent sign in required')
except auth.InvalidIdTokenError:
    return flask.abort(401, 'Invalid ID token')
except exceptions.FirebaseError:
    return flask.abort(401, 'Failed to create a session cookie')

يذهب

return func(w http.ResponseWriter, r *http.Request) {
	// Get the ID token sent by the client
	defer r.Body.Close()
	idToken, err := getIDTokenFromBody(r)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}

	decoded, err := client.VerifyIDToken(r.Context(), idToken)
	if err != nil {
		http.Error(w, "Invalid ID token", http.StatusUnauthorized)
		return
	}
	// Return error if the sign-in is older than 5 minutes.
	if time.Now().Unix()-decoded.Claims["auth_time"].(int64) > 5*60 {
		http.Error(w, "Recent sign-in required", http.StatusUnauthorized)
		return
	}

	expiresIn := time.Hour * 24 * 5
	cookie, err := client.SessionCookie(r.Context(), idToken, expiresIn)
	if err != nil {
		http.Error(w, "Failed to create a session cookie", http.StatusInternalServerError)
		return
	}
	http.SetCookie(w, &http.Cookie{
		Name:     "session",
		Value:    cookie,
		MaxAge:   int(expiresIn.Seconds()),
		HttpOnly: true,
		Secure:   true,
	})
	w.Write([]byte(`{"status": "success"}`))
}

سي #

// To ensure that cookies are set only on recently signed in users, check auth_time in
// ID token before creating a cookie.
var decodedToken = await FirebaseAuth.DefaultInstance.VerifyIdTokenAsync(idToken);
var authTime = new DateTime(1970, 1, 1).AddSeconds(
    (long)decodedToken.Claims["auth_time"]);

// Only process if the user signed in within the last 5 minutes.
if (DateTime.UtcNow - authTime < TimeSpan.FromMinutes(5))
{
    var options = new SessionCookieOptions()
    {
        ExpiresIn = TimeSpan.FromDays(5),
    };
    var sessionCookie = await FirebaseAuth.DefaultInstance.CreateSessionCookieAsync(
        idToken, options);
    // Set cookie policy parameters as required.
    this.Response.Cookies.Append("session", sessionCookie);
    return this.Ok();
}

// User did not sign in recently. To guard against ID token theft, require
// re-authentication.
return this.Unauthorized("Recent sign in required");

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

Node.js

// Whenever a user is accessing restricted content that requires authentication.
app.post('/profile', (req, res) => {
  const sessionCookie = req.cookies.session || '';
  // Verify the session cookie. In this case an additional check is added to detect
  // if the user's Firebase session was revoked, user deleted/disabled, etc.
  getAuth()
    .verifySessionCookie(sessionCookie, true /** checkRevoked */)
    .then((decodedClaims) => {
      serveContentForUser('/profile', req, res, decodedClaims);
    })
    .catch((error) => {
      // Session cookie is unavailable or invalid. Force user to login.
      res.redirect('/login');
    });
});

جافا

@POST
@Path("/profile")
public Response verifySessionCookie(@CookieParam("session") Cookie cookie) {
  String sessionCookie = cookie.getValue();
  try {
    // Verify the session cookie. In this case an additional check is added to detect
    // if the user's Firebase session was revoked, user deleted/disabled, etc.
    final boolean checkRevoked = true;
    FirebaseToken decodedToken = FirebaseAuth.getInstance().verifySessionCookie(
        sessionCookie, checkRevoked);
    return serveContentForUser(decodedToken);
  } catch (FirebaseAuthException e) {
    // Session cookie is unavailable, invalid or revoked. Force user to login.
    return Response.temporaryRedirect(URI.create("/login")).build();
  }
}

بايثون

@app.route('/profile', methods=['POST'])
def access_restricted_content():
    session_cookie = flask.request.cookies.get('session')
    if not session_cookie:
        # Session cookie is unavailable. Force user to login.
        return flask.redirect('/login')

    # Verify the session cookie. In this case an additional check is added to detect
    # if the user's Firebase session was revoked, user deleted/disabled, etc.
    try:
        decoded_claims = auth.verify_session_cookie(session_cookie, check_revoked=True)
        return serve_content_for_user(decoded_claims)
    except auth.InvalidSessionCookieError:
        # Session cookie is invalid, expired or revoked. Force user to login.
        return flask.redirect('/login')

يذهب

return func(w http.ResponseWriter, r *http.Request) {
	// Get the ID token sent by the client
	cookie, err := r.Cookie("session")
	if err != nil {
		// Session cookie is unavailable. Force user to login.
		http.Redirect(w, r, "/login", http.StatusFound)
		return
	}

	// Verify the session cookie. In this case an additional check is added to detect
	// if the user's Firebase session was revoked, user deleted/disabled, etc.
	decoded, err := client.VerifySessionCookieAndCheckRevoked(r.Context(), cookie.Value)
	if err != nil {
		// Session cookie is invalid. Force user to login.
		http.Redirect(w, r, "/login", http.StatusFound)
		return
	}

	serveContentForUser(w, r, decoded)
}

سي #

// POST: /profile
[HttpPost]
public async Task<ActionResult> Profile()
{
    var sessionCookie = this.Request.Cookies["session"];
    if (string.IsNullOrEmpty(sessionCookie))
    {
        // Session cookie is not available. Force user to login.
        return this.Redirect("/login");
    }

    try
    {
        // Verify the session cookie. In this case an additional check is added to detect
        // if the user's Firebase session was revoked, user deleted/disabled, etc.
        var checkRevoked = true;
        var decodedToken = await FirebaseAuth.DefaultInstance.VerifySessionCookieAsync(
            sessionCookie, checkRevoked);
        return ViewContentForUser(decodedToken);
    }
    catch (FirebaseAuthException)
    {
        // Session cookie is invalid or revoked. Force user to login.
        return this.Redirect("/login");
    }
}

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

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

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

Node.js

getAuth()
  .verifySessionCookie(sessionCookie, true)
  .then((decodedClaims) => {
    // Check custom claims to confirm user is an admin.
    if (decodedClaims.admin === true) {
      return serveContentForAdmin('/admin', req, res, decodedClaims);
    }
    res.status(401).send('UNAUTHORIZED REQUEST!');
  })
  .catch((error) => {
    // Session cookie is unavailable or invalid. Force user to login.
    res.redirect('/login');
  });

جافا

try {
  final boolean checkRevoked = true;
  FirebaseToken decodedToken = FirebaseAuth.getInstance().verifySessionCookie(
      sessionCookie, checkRevoked);
  if (Boolean.TRUE.equals(decodedToken.getClaims().get("admin"))) {
    return serveContentForAdmin(decodedToken);
  }
  return Response.status(Status.UNAUTHORIZED).entity("Insufficient permissions").build();
} catch (FirebaseAuthException e) {
  // Session cookie is unavailable, invalid or revoked. Force user to login.
  return Response.temporaryRedirect(URI.create("/login")).build();
}

بايثون

try:
    decoded_claims = auth.verify_session_cookie(session_cookie, check_revoked=True)
    # Check custom claims to confirm user is an admin.
    if decoded_claims.get('admin') is True:
        return serve_content_for_admin(decoded_claims)

    return flask.abort(401, 'Insufficient permissions')
except auth.InvalidSessionCookieError:
    # Session cookie is invalid, expired or revoked. Force user to login.
    return flask.redirect('/login')

يذهب

return func(w http.ResponseWriter, r *http.Request) {
	cookie, err := r.Cookie("session")
	if err != nil {
		// Session cookie is unavailable. Force user to login.
		http.Redirect(w, r, "/login", http.StatusFound)
		return
	}

	decoded, err := client.VerifySessionCookieAndCheckRevoked(r.Context(), cookie.Value)
	if err != nil {
		// Session cookie is invalid. Force user to login.
		http.Redirect(w, r, "/login", http.StatusFound)
		return
	}

	// Check custom claims to confirm user is an admin.
	if decoded.Claims["admin"] != true {
		http.Error(w, "Insufficient permissions", http.StatusUnauthorized)
		return
	}

	serveContentForAdmin(w, r, decoded)
}

سي #

try
{
    var checkRevoked = true;
    var decodedToken = await FirebaseAuth.DefaultInstance.VerifySessionCookieAsync(
        sessionCookie, checkRevoked);
    object isAdmin;
    if (decodedToken.Claims.TryGetValue("admin", out isAdmin) && (bool)isAdmin)
    {
        return ViewContentForAdmin(decodedToken);
    }

    return this.Unauthorized("Insufficient permissions");
}
catch (FirebaseAuthException)
{
    // Session cookie is invalid or revoked. Force user to login.
    return this.Redirect("/login");
}

خروج

عندما يقوم المستخدم بتسجيل الخروج من جانب العميل ، تعامل معه على جانب الخادم عبر نقطة نهاية. يجب أن يؤدي طلب POST / GET إلى مسح ملف تعريف ارتباط الجلسة. لاحظ أنه على الرغم من مسح ملف تعريف الارتباط ، فإنه يظل نشطًا حتى انتهاء صلاحيته الطبيعية.

Node.js

app.post('/sessionLogout', (req, res) => {
  res.clearCookie('session');
  res.redirect('/login');
});

جافا

@POST
@Path("/sessionLogout")
public Response clearSessionCookie(@CookieParam("session") Cookie cookie) {
  final int maxAge = 0;
  NewCookie newCookie = new NewCookie(cookie, null, maxAge, true);
  return Response.temporaryRedirect(URI.create("/login")).cookie(newCookie).build();
}

بايثون

@app.route('/sessionLogout', methods=['POST'])
def session_logout():
    response = flask.make_response(flask.redirect('/login'))
    response.set_cookie('session', expires=0)
    return response

يذهب

return func(w http.ResponseWriter, r *http.Request) {
	http.SetCookie(w, &http.Cookie{
		Name:   "session",
		Value:  "",
		MaxAge: 0,
	})
	http.Redirect(w, r, "/login", http.StatusFound)
}

سي #

// POST: /sessionLogout
[HttpPost]
public ActionResult ClearSessionCookie()
{
    this.Response.Cookies.Delete("session");
    return this.Redirect("/login");
}

يؤدي استدعاء واجهة برمجة التطبيقات للإلغاء إلى إبطال الجلسة وإلغاء جميع جلسات المستخدم الأخرى ، مما يفرض تسجيل دخول جديد. بالنسبة للتطبيقات الحساسة ، يُنصح بجلسة أقصر.

Node.js

app.post('/sessionLogout', (req, res) => {
  const sessionCookie = req.cookies.session || '';
  res.clearCookie('session');
  getAuth()
    .verifySessionCookie(sessionCookie)
    .then((decodedClaims) => {
      return getAuth().revokeRefreshTokens(decodedClaims.sub);
    })
    .then(() => {
      res.redirect('/login');
    })
    .catch((error) => {
      res.redirect('/login');
    });
});

جافا

@POST
@Path("/sessionLogout")
public Response clearSessionCookieAndRevoke(@CookieParam("session") Cookie cookie) {
  String sessionCookie = cookie.getValue();
  try {
    FirebaseToken decodedToken = FirebaseAuth.getInstance().verifySessionCookie(sessionCookie);
    FirebaseAuth.getInstance().revokeRefreshTokens(decodedToken.getUid());
    final int maxAge = 0;
    NewCookie newCookie = new NewCookie(cookie, null, maxAge, true);
    return Response.temporaryRedirect(URI.create("/login")).cookie(newCookie).build();
  } catch (FirebaseAuthException e) {
    return Response.temporaryRedirect(URI.create("/login")).build();
  }
}

بايثون

@app.route('/sessionLogout', methods=['POST'])
def session_logout():
    session_cookie = flask.request.cookies.get('session')
    try:
        decoded_claims = auth.verify_session_cookie(session_cookie)
        auth.revoke_refresh_tokens(decoded_claims['sub'])
        response = flask.make_response(flask.redirect('/login'))
        response.set_cookie('session', expires=0)
        return response
    except auth.InvalidSessionCookieError:
        return flask.redirect('/login')

يذهب

return func(w http.ResponseWriter, r *http.Request) {
	cookie, err := r.Cookie("session")
	if err != nil {
		// Session cookie is unavailable. Force user to login.
		http.Redirect(w, r, "/login", http.StatusFound)
		return
	}

	decoded, err := client.VerifySessionCookie(r.Context(), cookie.Value)
	if err != nil {
		// Session cookie is invalid. Force user to login.
		http.Redirect(w, r, "/login", http.StatusFound)
		return
	}
	if err := client.RevokeRefreshTokens(r.Context(), decoded.UID); err != nil {
		http.Error(w, "Failed to revoke refresh token", http.StatusInternalServerError)
		return
	}

	http.SetCookie(w, &http.Cookie{
		Name:   "session",
		Value:  "",
		MaxAge: 0,
	})
	http.Redirect(w, r, "/login", http.StatusFound)
}

سي #

// POST: /sessionLogout
[HttpPost]
public async Task<ActionResult> ClearSessionCookieAndRevoke()
{
    var sessionCookie = this.Request.Cookies["session"];
    try
    {
        var decodedToken = await FirebaseAuth.DefaultInstance
            .VerifySessionCookieAsync(sessionCookie);
        await FirebaseAuth.DefaultInstance.RevokeRefreshTokensAsync(decodedToken.Uid);
        this.Response.Cookies.Delete("session");
        return this.Redirect("/login");
    }
    catch (FirebaseAuthException)
    {
        return this.Redirect("/login");
    }
}

تحقق من ملفات تعريف الارتباط للجلسة باستخدام مكتبة JWT لجهة خارجية

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

تحقق من أن عنوان ملف تعريف ارتباط الجلسة يتوافق مع القيود التالية:

مطالبات رؤوس ملفات تعريف الارتباط لجلسة Firebase
alg الخوارزمية "RS256"
kid معرف المفتاح يجب أن تتوافق مع أحد المفاتيح العامة المدرجة على https://www.googleapis.com/identitytoolkit/v3/relyingparty/publicKeys

تحقق من أن حمولة ملف تعريف ارتباط الجلسة تتوافق مع القيود التالية:

مطالبات حمولة ملفات تعريف الارتباط لجلسة Firebase
exp تاريخ انتهاء الصلاحية يجب أن يكون في المستقبل. يتم قياس الوقت بالثواني منذ عهد UNIX. يتم تحديد انتهاء الصلاحية بناءً على المدة المخصصة المقدمة عند إنشاء ملف تعريف الارتباط.
iat صدر في وقت يجب أن يكون في الماضي. يتم قياس الوقت بالثواني منذ عهد UNIX.
aud جمهور يجب أن يكون معرّف مشروع Firebase ، المعرّف الفريد لمشروع Firebase الخاص بك ، والذي يمكن العثور عليه في عنوان URL لوحدة تحكم المشروع.
iss المُصدر يجب أن يكون "https://session.firebase.google.com/<projectId>" "، حيث يكون <projectId> هو نفس معرف المشروع المستخدم في aud أعلاه.
sub موضوع يجب أن تكون سلسلة غير فارغة ويجب أن تكون uid المستخدم أو الجهاز.
auth_time وقت المصادقة يجب أن يكون في الماضي. وقت مصادقة المستخدم. يتطابق هذا مع وقت auth_time لرمز المعرف المميز المستخدم لإنشاء ملف تعريف ارتباط الجلسة.

أخيرًا ، تأكد من توقيع ملف تعريف ارتباط الجلسة بواسطة المفتاح الخاص المطابق لمطالبة طفل الرمز المميز. احصل على المفتاح العام من https://www.googleapis.com/identitytoolkit/v3/relyingparty/publicKeys واستخدم مكتبة JWT للتحقق من التوقيع. استخدم قيمة max-age في رأس Cache-Control للاستجابة من نقطة النهاية لتحديد وقت تحديث المفاتيح العامة.

إذا نجحت جميع عمليات التحقق المذكورة أعلاه ، فيمكنك استخدام الموضوع ( sub ) الخاص بملف تعريف ارتباط الجلسة كمعرّف المستخدم للمستخدم أو الجهاز المقابل.