Supabase и Astro
Supabase — это альтернатива Firebase с открытым исходным кодом. Она предоставляет базу данных Postgres, аутентификацию, edge-функции, подписки в реальном времени и хранилище.
Инициализация Supabase в Astro
Заголовок раздела Инициализация Supabase в AstroНеобходимые условия
Заголовок раздела Необходимые условия- Проект Supabase. Если у вас его нет, вы можете бесплатно зарегистрироваться на сайте supabase.com и создать новый проект.
- Проект Astro с включенным серверным рендерингом (SSR).
- Учётные данные Supabase для вашего проекта. Вы можете найти их на вкладке Settings > API вашего проекта Supabase.
- SUPABASE_URL: URL-адрес вашего проекта Supabase.
- SUPABASE_ANON_KEY: Анонимный ключ для вашего проекта Supabase.
 
Добавление учётных данных Supabase
Заголовок раздела Добавление учётных данных SupabaseЧтобы добавить учётные данные Supabase в проект Astro, добавьте следующее в файл .env:
SUPABASE_URL=ВАШ_SUPABASE_URLSUPABASE_ANON_KEY=ВАШ_SUPABASE_ANON_КЛЮЧТеперь эти переменные окружения доступны в вашем проекте.
Если вы хотите иметь IntelliSense для ваших переменных окружения, отредактируйте или создайте env.d.ts в вашем каталоге src/ и добавьте следующее:
interface ImportMetaEnv {  readonly SUPABASE_URL: string  readonly SUPABASE_ANON_KEY: string}
interface ImportMeta {  readonly env: ImportMetaEnv}Подробнее о переменных окружения и файлах .env в Astro.
Теперь ваш проект должен включать эти файлы:
- Директорияsrc/- env.d.ts
 
- .env
- astro.config.mjs
- package.json
Установка зависимостей
Заголовок раздела Установка зависимостейЧтобы подключиться к Supabase, вам необходимо установить @supabase/supabase-js в ваш проект.
npm install @supabase/supabase-jspnpm add @supabase/supabase-jsyarn add @supabase/supabase-jsДалее создайте папку с именем lib в каталоге src/. В нее вы добавите клиент Supabase.
В supabase.ts добавьте следующее для инициализации клиента Supabase:
import { createClient } from "@supabase/supabase-js";
export const supabase = createClient(  import.meta.env.SUPABASE_URL,  import.meta.env.SUPABASE_ANON_KEY,);Теперь ваш проект должен включать эти файлы:
- Директорияsrc/- Директорияlib/- supabase.ts
 
- env.d.ts
 
- .env
- astro.config.mjs
- package.json
Добавление аутентификации с помощью Supabase
Заголовок раздела Добавление аутентификации с помощью SupabaseSupabase обеспечивает аутентификацию из коробки. Она поддерживает аутентификацию по электронной почте/паролю и аутентификацию по протоколу OAuth со многими провайдерами, включая GitHub, Google и некоторые другие.
Необходимые условия
Заголовок раздела Необходимые условия- Проект Astro, инициализированный с Supabase.
- Проект Supabase с включенной аутентификацией по электронной почте/паролю. Включить эту функцию можно на вкладке Authentication > Providers в настройках проекта.
Создание конечных точек сервера аутентификации
Заголовок раздела Создание конечных точек сервера аутентификацииЧтобы добавить аутентификацию в ваш проект, вам нужно создать несколько конечных точек сервера. Эти конечные точки будут использоваться для регистрации, входа и выхода пользователей.
- POST /api/auth/register: для регистрации нового пользователя.
- POST /api/auth/signin: для авторизации пользователя.
- GET /api/auth/signout: для выхода пользователя из системы.
Создайте эти конечные точки в директории src/pages/api/auth вашего проекта. Теперь ваш проект должен включать эти новые файлы:
- Директорияsrc/- Директорияlib/- supabase.ts
 
- Директорияpages/- Директорияapi/- Директорияauth/- signin.ts
- signout.ts
- register.ts
 
 
 
- env.d.ts
 
- .env
- astro.config.mjs
- package.json
register.ts создаёт нового пользователя в Supabase. Он принимает запрос POST с указанием электронной почты и пароля. Затем он использует Supabase SDK для создания нового пользователя.
import type { APIRoute } from "astro";import { supabase } from "../../../lib/supabase";
export const POST: APIRoute = async ({ request, redirect }) => {  const formData = await request.formData();  const email = formData.get("email")?.toString();  const password = formData.get("password")?.toString();
  if (!email || !password) {    return new Response("Требуется ввести email и пароль", { status: 400 });  }
  const { error } = await supabase.auth.signUp({    email,    password,  });
  if (error) {    return new Response(error.message, { status: 500 });  }
  return redirect("/signin");};signin.ts авторизирует пользователя. Он принимает запрос POST с указанием электронной почты и пароля. Затем он использует Supabase SDK для регистрации пользователя.
import type { APIRoute } from "astro";import { supabase } from "../../../lib/supabase";
export const POST: APIRoute = async ({ request, cookies, redirect }) => {  const formData = await request.formData();  const email = formData.get("email")?.toString();  const password = formData.get("password")?.toString();
  if (!email || !password) {    return new Response("Требуется ввести email и пароль", { status: 400 });  }
  const { data, error } = await supabase.auth.signInWithPassword({    email,    password,  });
  if (error) {    return new Response(error.message, { status: 500 });  }
  const { access_token, refresh_token } = data.session;  cookies.set("sb-access-token", access_token, {    path: "/",  });  cookies.set("sb-refresh-token", refresh_token, {    path: "/",  });  return redirect("/dashboard");};В signout.ts происходит выход пользователя из системы. Он принимает запрос GET и удаляет токены доступа и обновления пользователя.
import type { APIRoute } from "astro";
export const GET: APIRoute = async ({ cookies, redirect }) => {  cookies.delete("sb-access-token", { path: "/" });  cookies.delete("sb-refresh-token", { path: "/" });  return redirect("/signin");};Создание страниц авторизации
Заголовок раздела Создание страниц авторизацииТеперь, когда вы создали конечные точки сервера, создайте страницы, которые будут их использовать.
- src/pages/register: содержит форму для регистрации нового пользователя.
- src/pages/signin: содержит форму для авторизации пользователя.
- src/pages/dashboard: содержит страницу, доступную только для авторизованных пользователей.
Создайте эти страницы в каталоге src/pages. Теперь ваш проект должен включать эти новые файлы:
- Директорияsrc/- Директорияlib/- supabase.ts
 
- Директорияpages/- Директорияapi/- Директорияauth/- signin.ts
- signout.ts
- register.ts
 
 
- register.astro
- signin.astro
- dashboard.astro
 
- env.d.ts
 
- .env
- astro.config.mjs
- package.json
register.astro содержит форму для регистрации нового пользователя. Она принимает электронную почту и пароль и отправляет POST-запрос на /api/auth/register.
---import Layout from "../layouts/Layout.astro";---
<Layout title="Регистрация">  <h1>Регистрация</h1>  <p>У вас уже есть аккаунт? <a href="/signin">Войти</a></p>  <form action="/api/auth/register" method="post">    <label for="email">Email</label>    <input type="email" name="email" id="email" />    <label for="password">Пароль</label>    <input type="password" name="password" id="password" />    <button type="submit">Войти</button>  </form></Layout>В signin.astro содержится форма для авторизации пользователя. Она принимает электронную почту и пароль и отправляет POST запрос на /api/auth/signin. Она также проверяет наличие токенов доступа и обновления. Если они присутствуют, то происходит перенаправление на приборную панель.
---import Layout from "../layouts/Layout.astro";
const { cookies, redirect } = Astro;
const accessToken = cookies.get("sb-access-token");const refreshToken = cookies.get("sb-refresh-token");
if (accessToken && refreshToken) {  return redirect("/dashboard");}---
<Layout title="Авторизация">  <h1>Авторизация</h1>  <p>Вы здесь впервые? <a href="/register">Создание учётной записи</a></p>  <form action="/api/auth/signin" method="post">    <label for="email">Email</label>    <input type="email" name="email" id="email" />    <label for="password">Пароль</label>    <input type="password" name="password" id="password" />    <button type="submit">Войти</button>  </form></Layout>dashboard.astro содержит страницу, доступную только для авторизованных пользователей. Она проверяет наличие токенов доступа и обновления. Если их нет, она перенаправляет на страницу авторизации.
---import Layout from "../layouts/Layout.astro";import { supabase } from "../lib/supabase";
const { cookies, redirect } = Astro;
const accessToken = cookies.get("sb-access-token");const refreshToken = cookies.get("sb-refresh-token");
if (!accessToken || !refreshToken) {  return redirect("/signin");}
const { data, error } = await supabase.auth.setSession({  refresh_token: refreshToken.value,  access_token: accessToken.value,});
if (error) {  cookies.delete("sb-access-token", {    path: "/",  });  cookies.delete("sb-refresh-token", {    path: "/",  });
  return redirect("/signin");}
const email = data.user?.email;---<Layout title="dashboard">  <h1>Добро пожаловать, {email}</h1>  <p>Мы рады видеть вас здесь</p>  <form action="/api/auth/signout">    <button type="submit">Выйти</button>  </form></Layout>Добавление аутентификации OAuth
Заголовок раздела Добавление аутентификации OAuthЧтобы добавить OAuth-аутентификацию в ваш проект, вам нужно отредактировать клиент Supabase, чтобы включить поток аутентификации с помощью pkce. Подробнее о потоках аутентификации вы можете прочитать в документации Supabase.
import { createClient } from "@supabase/supabase-js";
export const supabase = createClient(  import.meta.env.SUPABASE_URL,  import.meta.env.SUPABASE_ANON_KEY,  {    auth: {      flowType: "pkce",    },  },);Далее в приборной панели Supabase включите провайдер OAuth, который вы хотите использовать. Список поддерживаемых провайдеров можно найти на вкладке Authentication > Providers вашего проекта Supabase.
В следующем примере в качестве провайдера OAuth используется GitHub. Чтобы подключить свой проект к GitHub, выполните действия, описанные в документации Supabase.
Затем создайте новую конечную точку сервера для обработки обратного вызова OAuth в src/pages/api/auth/callback.ts. Эта конечная точка будет использоваться для обмена кода OAuth на токен доступа и обновления.
import type { APIRoute } from "astro";import { supabase } from "../../../lib/supabase";
export const GET: APIRoute = async ({ url, cookies, redirect }) => {  const authCode = url.searchParams.get("code");
  if (!authCode) {    return new Response("No code provided", { status: 400 });  }
  const { data, error } = await supabase.auth.exchangeCodeForSession(authCode);
  if (error) {    return new Response(error.message, { status: 500 });  }
  const { access_token, refresh_token } = data.session;
  cookies.set("sb-access-token", access_token, {    path: "/",  });  cookies.set("sb-refresh-token", refresh_token, {    path: "/",  });
  return redirect("/dashboard");};Далее отредактируйте страницу входа и добавьте новую кнопку для входа с провайдером OAuth. Эта кнопка должна отправлять POST-запрос на /api/auth/signin с provider, установленным на имя OAuth-провайдера.
---import Layout from "../layouts/Layout.astro";
const { cookies, redirect } = Astro;
const accessToken = cookies.get("sb-access-token");const refreshToken = cookies.get("sb-refresh-token");
if (accessToken && refreshToken) {  return redirect("/dashboard");}---
<Layout title="Авторизация">  <h1>Авторизация</h1>  <p>Вы здесь впервые? <a href="/register">Создать учётную запись</a></p>  <form action="/api/auth/signin" method="post">    <label for="email">Email</label>    <input type="email" name="email" id="email" />    <label for="password">Пароль</label>    <input type="password" name="password" id="password" />    <button type="submit">Авторизоваться</button>    <button value="github" name="provider" type="submit">Войти в систему через GitHub</button>  </form></Layout>Наконец, отредактируйте конечную точку сервера входа для работы с провайдером OAuth. Если присутствует provider, он будет перенаправлять на провайдера OAuth. В противном случае он будет регистрировать пользователя с помощью электронной почты и пароля.
import type { APIRoute } from "astro";import { supabase } from "../../../lib/supabase";import type { Provider } from "@supabase/supabase-js";
export const POST: APIRoute = async ({ request, cookies, redirect }) => {  const formData = await request.formData();  const email = formData.get("email")?.toString();  const password = formData.get("password")?.toString();  const provider = formData.get("provider")?.toString();
  const validProviders = ["google", "github", "discord"];
  if (provider && validProviders.includes(provider)) {    const { data, error } = await supabase.auth.signInWithOAuth({      provider: provider as Provider,      options: {        redirectTo: "http://localhost:4321/api/auth/callback"      },    });
    if (error) {      return new Response(error.message, { status: 500 });    }
    return redirect(data.url);  }
  if (!email || !password) {    return new Response("Необходимо указать электронную почту и пароль", { status: 400 });  }
  const { data, error } = await supabase.auth.signInWithPassword({    email,    password,  });
  if (error) {    return new Response(error.message, { status: 500 });  }
  const { access_token, refresh_token } = data.session;  cookies.set("sb-access-token", access_token, {    path: "/",  });  cookies.set("sb-refresh-token", refresh_token, {    path: "/",  });  return redirect("/dashboard");};После создания конечной точки обратного вызова OAuth и редактирования страницы входа и конечной точки сервера ваш проект должен иметь следующую структуру файлов:
- Директорияsrc/- Директорияlib/- supabase.ts
 
- Директорияpages/- Директорияapi/- Директорияauth/- signin.ts
- signout.ts
- register.ts
- callback.ts
 
 
- register.astro
- signin.astro
- dashboard.astro
 
- env.d.ts
 
- .env
- astro.config.mjs
- package.json
Ресурсы сообщества
Заголовок раздела Ресурсы сообщества- Проникнитесь духом праздника с помощью Astro, React и Supabase
- Демонстрация авторизации Astro и Supabase