Как добавить аутентификацию Supabase к приложению на Vue

В этой статье мы рассмотрим, как настроить аутентификацию с помощью Supabase и Vue 3.

Описанный метод подходит и для Vue 2, но понадобится изменить настройки, чтобы работать с API Options. Я же пользуюсь Vue 3, поскольку теперь это версия по умолчанию.

Здесь не будет уделено много внимания стилю программирования. В основном сосредоточимся на аутентификации поверх базы данных.

Требования

Вам нужно быть знакомым с JavaScript и иметь опыт работы с Vue 3. Опыт работы с Supabase пригодится, но не обязателен.

Вам также понадобится установить на компьютер Node.js и NPM.

Начало работы

Начнем с интерфейса. В первую очередь настроим проект.

Откройте терминал и внутри папки, в которой хотите разместить проект, выполните команду:

npm init vite@latest vue-supabase-auth --template vue

Она инициализирует новый проект Vite с помощью Vue 3 в папке с именем vue-supabase-auth.

Запустите его в редакторе кода и откройте файл App.vue внутри папки src. Когда я инициализировал проект, Vite поместил тег script над тегом template. Я решил переместить тег шаблона наверх, но в этом нет необходимости.

Добавьте аутентификацию в приложение

Следующий шаг  —  добавить аутентификацию в приложение. Supabase дает возможность аутентифицировать пользователя многими различными способами.

Мы рассмотрим, как настроить базовую аутентификацию по электронной почте/паролю и аутентификацию с помощью “волшебной ссылки”. “Волшебная ссылка”  —  это просто ссылка, отправленная на электронную почту пользователя, при нажатии на которую он попадет в приложение и войдет в систему.

Создайте учетную запись Supabase

Зарегистрируйтесь на Supabase, если еще этого не сделали.

Как только вы войдете в систему, нажмите на зеленую кнопку с надписью “New project” (“Новый проект”) и выберите организацию по умолчанию, которая была создана при входе в систему. Моя называлась “Организация Брайанбэрроу” (по моему имени).

После появится окно, где вы предоставите некоторую информацию о проекте. Я назову его basic-auth, дам ему надежный пароль, а затем выберу регион “Запад США (Северная Калифорния)”, потому что он ближе всего ко мне.

Как только настройка проекта завершится, перейдите в раздел “Аутентификация” -> “Настройки” и отключите опцию “Включить подтверждение по электронной почте”. Так будет удобнее в рамках этого руководства.

Настройка Supabase в проекте Vue

Во-первых, нам нужно запустить npm install @supabase/supabase-js, чтобы получить пакет JavaScript для интеграции с Supabase.

Затем нужно создать файл supabase.js в папке src проекта. Он должен содержать следующее:

import { createClient } from '@supabase/supabase-js'

const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY

export const supabase = createClient(supabaseUrl, supabaseAnonKey)

В приведенном выше коде нужно настроить переменные среды, которые содержат ключи Supabase. Создайте файл env.local в корне проекта и добавьте VITE_SUPABASE_URL и VITE_SUPABASE_ANON_KEY. Вы можете найти свой URL-адрес и anon_key на панели инструментов проекта Supabase.

Файл env.local будет выглядеть так:

VITE_SUPABASE_URL=YOUR_SUPABASE_URL
VITE_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY

Мы также создадим центральное хранилище для данных, которые необходимы во всем приложении (например, информация о пользователе). Создайте файл store.js в папке src и заполните его этим кодом:

import { reactive } from "vue";

export const store = {
state: reactive({
user: {},
}),
};

Создание компонентов входа и регистрации

Проверка подлинности на Supabase разделяет процессы входа и регистрации, поэтому нам нужно обрабатывать их по-разному. Для ясности я решил создать два отдельных компонента.

Создайте файл SignUp.vue в папке components и добавьте следующий код:

<template>
<div>
<h2>Sign up for an account</h2>
<form @submit.prevent="handleSignup">
<div>
<label for="email">Email</label>
<input id="email" type="email" v-model="email" />
</div>
<div>
<label for="password">Password</label>
<input id="password" type="password" v-model="password" />
</div>
<div>
<button type="submit">Sign up</button>
</div>
</form>
</div>
</template>

<script>
import { ref } from "vue";
import { supabase } from "../supabase";

export default {
setup() {
const email = ref("");
const password = ref("");

const handleSignup = async () => {
try {
// Задействуем предоставленный Supabase метод для обработки регистрации
const { error } = await supabase.auth.signUp({
email: email.value,
password: password.value,
});
if (error) throw error;
} catch (error) {
alert(error.error_description || error.message);
}
};

return {
email,
password,
handleSignup,
};
},
};
</script>

Теперь создайте файл SignIn.vue и добавьте туда приведенный ниже код. Единственные различия  —  в именах вызываемых методов, также немного отличается текст в разметке.

<template>
<div>
<h2>Sign in to your account</h2>
<form @submit.prevent="handleSignin">
<div>
<label for="email">Email</label>
<input id="email" type="email" v-model="email" />
</div>
<div>
<label for="password">Password</label>
<input id="password" type="password" v-model="password" />
</div>
<div>
<button type="submit">Sign in</button>
</div>
</form>
</div>
</template>

<script>
import { ref } from "vue";
import { supabase } from "../supabase";

export default {
setup() {
const email = ref("");
const password = ref("");

const handleSignin = async () => {
try {
// Задействуем предоставленный Supabase метод для обработки входа
const { error } = await supabase.auth.signIn({
email: email.value,
password: password.value,
});
if (error) throw error;
} catch (error) {
alert(error.error_description || error.message);
}
};

return {
email,
password,
handleSignin,
};
},
};
</script>

Теперь стоит добавить компонент-обертку над этими двумя. Создайте файл Auth.vue и вставьте туда следующий код:

<template>
<div>
<sign-up v-if="isSignUp" />
<sign-in v-else />
<button @click="isSignUp = !isSignUp">
{{
isSignUp
? "Already have an account? Sign In"
: "Don't have an account yet? Sign Up"
}}
</button>
</div>
</template>

<script>
import { ref } from "vue";
import SignUp from "./SignUp.vue";
import SignIn from "./SignIn.vue";
export default {
components: { SignUp, SignIn },
setup() {
const isSignUp = ref(true);

return {
isSignUp,
};
},
};
</script>

<style scoped></style>

Это позволит пользователю переключаться между представлениями входа и регистрации. Теперь снова откройте App.vue и обновите код:

<template>
<!-- Проверка доступности пользователя в хранилище; при недоступности - показываем компонент авторизации-->
<Auth v-if="!store.state.user" />
<!-- Если пользователь доступен, показываем компонент Hello World -->
<HelloWorld v-else msg="Hello Vue 3 + Vite" />
</template>

<script>
import Auth from "./components/Auth.vue";
import HelloWorld from "./components/HelloWorld.vue";

import { store } from "./store";
import { supabase } from "./supabase";

export default {
components: {
HelloWorld,
Auth,
},
setup() {
// сначала проверяем, вошел ли пользователь в систему с помощью Supabase
store.state.user = supabase.auth.user();
// затем настраиваем слушатель для обновления хранилища, если меняется пользователь - выходит из системы или входит
supabase.auth.onAuthStateChange((event, session) => {
if (event == "SIGNED_OUT") {
store.state.user = null;
} else {
store.state.user = session.user;
}
});

return {
store,
};
},
};
</script>

<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

Теперь если пользователь не вошел в систему, то у него отобразится компонент аутентификации. В противном случае отобразится HelloWorld.vue, как мы изначально и настроили.

Форма входа

Зарегистрируйтесь, используя действующий адрес электронной почты и пароль. После вы должны снова увидеть компонент HelloWorld.

Компонент Hello World, который отображается после регистрации

Как выйти из системы

Это довольно просто. Внутри компонента HelloWorld добавьте следующее в нижнюю часть тега шаблона:

<button @click="signOut">Sign Out</button>

Затем обновите тег script в HelloWorld до этого:

<script setup>
import { ref } from "vue";
import { supabase } from "../supabase";

defineProps({
msg: String,
});

const count = ref(0);
async function signOut() {
const { error } = await supabase.auth.signOut();
}
</script>

Мы импортируем файл supabase, созданный ранее, а затем добавляем метод выхода signOut, который вызывается при нажатии кнопки.

Аутентификация с помощью волшебной ссылки

Supabase также предоставляет возможность отправлять на электронную почту волшебную ссылку, по которой можно кликнуть  —  это приводит пользователя в приложение и авторизует его. Ссылка, которую формирует Supabase, перенаправит на сайт, поэтому нужно убедиться, что в нашем распоряжении есть правильный URL-адрес перенаправления и он задан в настройках Supabase.

Перейдите на страницу “Авторизация” -> “Настройки” на панели управления Supabase для вашего проекта и убедитесь, что URL localhost указан в поле “Site URL”.

Создайте в папке компонентов новый файл с именем MagicLink.vue и добавьте следующий код:

<template>
<div>
<h2>Sign in With Magic Link</h2>
<form @submit.prevent="handleMagicLink">
<div>
<label for="email">Email</label>
<input id="email" type="email" v-model="email" />
</div>
<div>
<button type="submit">Sign in</button>
</div>
</form>
</div>
</template>

<script>
import { ref } from "vue";
import { supabase } from "../supabase";

export default {
setup() {
const email = ref("");

const handleMagicLink = async () => {
try {
// Мы вызываем метод входа из Supabase, чтобы отправить волшебную ссылку. Передаем ему только электронную почту.
const { error } = await supabase.auth.signIn({
email: email.value,
});
if (error) throw error;
} catch (error) {
alert(error.error_description || error.message);
}
};

return {
email,
handleMagicLink,
};
},
};
</script>

Этот компонент похож на компонент входа в систему. Он использует тот же метод, но чтобы получить волшебную ссылку, мы передаем только электронную почту.

Теперь нужно обновить Auth.vue, чтобы он также задействовал компонент MagicLink. Обновите Auth.vue до следующего:

<template>
<div>
<!-- логика v-if для определения, какой компонент отображать -->
<sign-up v-if="isSignUp && !useMagicLink" />
<sign-in v-else-if="!isSignUp && !useMagicLink" />
<magic-link v-else />
<div v-if="!useMagicLink">
<button v-if="!useMagicLink" @click="isSignUp = !isSignUp">
{{
isSignUp
? "Already have an account? Sign In"
: "Don't have an account yet? Sign Up"
}}
</button>
<p>Or</p>
</div>
<button @click="toggleMagicLink">
{{
useMagicLink
? "Sign in with email and password"
: "Sign in with magic link"
}}
</button>
</div>
</template>

<script>
import { ref } from "vue";
import SignUp from "./SignUp.vue";
import SignIn from "./SignIn.vue";
import MagicLink from "./MagicLink.vue";
export default {
components: { SignUp, SignIn, MagicLink },
setup() {
const isSignUp = ref(true);
const useMagicLink = ref(false);

function toggleMagicLink() {
useMagicLink.value = !useMagicLink.value;
}

return {
isSignUp,
useMagicLink,

toggleMagicLink,
};
},
};
</script>

<style scoped></style>

Теперь страница авторизации по умолчанию должна выглядеть следующим образом:

И так, если пользователь нажимает на кнопку “Войти по волшебной ссылке”:

Если вы введете адрес электронной почты и нажмете “Войти”, то должны получить письмо с волшебной ссылкой. Нажмите на эту ссылку, и вы будете перенаправлены в приложение как авторизованный пользователь, где увидите экран HelloWorld.

Вывод

Supabase упрощает настройку аутентификации. Также он обеспечивает аутентификацию с помощью Google, Apple, Github и многих других провайдеров.

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Brian Barrow: How to Add Supabase Authentication to a Vue App

Предыдущая статьяЧто говорить на поведенческом интервью по науке о данных
Следующая статьяИнтеграция ChatGPT с Node.js: руководство для начинающих