انتقل إلى المحتوى

تسجيل الدخول المشترك

auth.hasanat.dev خدمة تسجيل دخول مشتركة لكل المواقع التي تعمل على نطاقات hasanat.dev. يسجّل المستخدم دخوله مرة واحدة بحساب Google أو GitHub، فيعرفه كل موقع من مواقع حسنات.

  • بعد تسجيل الدخول تضع الخدمة ملف تعريف الارتباط authjs.session-token على النطاق .hasanat.dev. يرسله المتصفح إلى كل موقع على https://*.hasanat.dev.
  • الملف مشفّر بسرّ لا تملكه إلا خدمة الدخول، فلا يفكّه تطبيقك. يسأل تطبيقك الخدمة بدلًا من ذلك: يرسل ترويسة cookie كما وصلته إلى https://auth.hasanat.dev/api/auth/session، فيصله بيان الجلسة، أو null إن لم يكن أحد مسجّلًا.
  • الملف httpOnly وSecure وSameSite=Lax، فلا تقرؤه شيفرة الصفحة.
  • تنتهي الجلسة بعد 30 يومًا دون استخدام، وكل فحص للجلسة يمدّدها.
  • صفحة الدخول: https://auth.hasanat.dev/api/auth/signin?callbackUrl=<رابط العودة بعد ترميزه>
  • بيان الجلسة: https://auth.hasanat.dev/api/auth/session
  • تسجيل الخروج: https://auth.hasanat.dev/api/auth/signout
  • حساب المستخدم: https://auth.hasanat.dev/account

تقبل الخدمة رابط العودة إن كان https://hasanat.dev، أو نطاقًا فرعيًا من مستوى واحد مثل https://name.hasanat.dev، أو http://localhost. أي رابط آخر يعيد المستخدم إلى auth.hasanat.dev نفسها. صفحة الدخول بالإنجليزية حاليًا.

{
"user": {
"id": "…",
"name": "…",
"email": "…",
"image": "…",
"provider": "google",
"githubUsername": null,
"role": "user"
},
"expires": "…"
}
  • id معرّف ثابت للمستخدم. اربط به بيانات تطبيقك.
  • provider هو google أو github.
  • role من سجل المستخدم في خدمة الدخول، وقيمته الافتراضية user، ويُقرأ عند تسجيل الدخول. ليس دورًا في مشاريع حسنات مثل القائد أو المشرف. احفظ صلاحيات تطبيقك في قاعدة بياناته.

القالب مربوط بالخدمة مسبقًا. الملف src/middleware.ts يسأل خدمة الدخول عن الجلسة، ويضع المستخدم في Astro.locals.user، أو null.

---
// صفحة تحتاج تسجيل الدخول
import { requireAuth } from "@/lib/auth";
const redirect = requireAuth(Astro.locals.user, Astro.url.href);
if (redirect) return redirect;
const user = Astro.locals.user; // { id, name, email, image, role }
---
// روابط الدخول والخروج، وفحص المسؤول
import { getSignInUrl, getSignOutUrl, isAdmin } from "@/lib/auth";
const signIn = getSignInUrl(Astro.url.href);
const signOut = getSignOutUrl();
const admin = isAdmin(Astro.locals.user); // role === "admin"
// مسار API محمي
import type { APIRoute } from "astro";
export const GET: APIRoute = async ({ locals }) => {
if (!locals.user) return new Response("Unauthorized", { status: 401 });
return Response.json({ id: locals.user.id });
};

الصفحات التي تعمل على نطاق فرعي من hasanat.dev تستطيع أن تسأل عن الجلسة من المتصفح، لأن خدمة الدخول تقبل الطلبات المصحوبة بملفات الارتباط من نطاقات hasanat.dev:

const res = await fetch("https://auth.hasanat.dev/api/auth/session", {
credentials: "include",
});
const session = await res.json(); // null إن لم يكن المستخدم مسجّلًا

لا يعمل تسجيل الدخول المشترك على localhost، لأن ملف الارتباط خاص بنطاقات hasanat.dev فلا يُرسل إلى جهازك. في وضع التطوير يوجّه القالب روابط الدخول إلى http://localhost:8788، وهي نسخة محلية من خدمة الدخول لا يشغّلها أغلب البنّائين، فمستودعها خاص.

لذلك يبقى Astro.locals.user فارغًا على جهازك. ابنِ الصفحات العامة أولًا، وجرّب تسجيل الدخول بعد النشر على نطاق فرعي من hasanat.dev.

التطبيقات خارج نطاقات hasanat.dev

رابط قسم «التطبيقات خارج نطاقات hasanat.dev»

لا يوجد اليوم تدفق OAuth للتطبيقات الخارجية. الروابط auth.hasanat.dev/oauth/authorize و/oauth/token غير موجودة، ولا تُصدر معرّفات أو أسرار للعملاء. السطران المعلّقان HASANAT_CLIENT_ID وHASANAT_CLIENT_SECRET في ملف .env.example في القالب لا يُستخدمان.

لتستخدم حسابات حسنات في تطبيق خارجي:

  1. اعرضه على نطاق فرعي من hasanat.dev إن أمكن، فيعمل تسجيل الدخول المشترك. انظر النشر والنطاقات الفرعية.
  2. أو اطلب «تسجيل دخول لتطبيق خارجي» من لوحة المنصة، ويبحث مسؤول الخدمات وضعك معك.

يصل تطبيقك من خدمة الدخول: معرّف المستخدم، واسمه، وبريده، وصورته. تحدّد سياسة البيانات في القالب ما يجوز:

  • استخدم المعرّف لربط بيانات المستخدم في تطبيقك، واعرض اسمه وصورته.
  • لا تحفظ البريد أو الصورة في قاعدتك إلا إن احتاجها التطبيق وأفصحت عن ذلك.
  • لا تشارك بيانات المستخدمين مع أي طرف آخر، ولا تبعها، ولا تستخدمها للإعلانات.
  • ضع في التطبيق ملاحظة خصوصية قصيرة يصل إليها المستخدم، ولو رابطًا في التذييل.
  • لا تطلب AUTH_SECRET أو تنسخه إلى تطبيقك. لا يحتاجه التطبيق، ولا يُرسل في أي طلب.
  • لا تحفظ كلمات مرور أو رموز دخول أو ملف الجلسة نفسه.
  • لا تحاول فكّ ملف الجلسة بنفسك: اسأل خدمة الدخول.
  • لا تضف مزوّد دخول آخر، مثل Firebase Auth أو Clerk، إلى تطبيقات القالب.