如何使用 Supabase 在 SolidJS 应用程序中集成用户身份验证

介绍

绝大多数应用程序要求用户验证身份;因为网站和应用程序的安全性至关重要。通过身份验证验证用户的身份是几个应用程序用于处理安全性的程序;这主要是为了防止公众了解私人信息,并防止用户代表他人行动。

Supabase是Firebase的免费和开源替代方案,它是一个BaaS(Backend as a Service)平台,为您提供多种工具和服务,帮助您创建和维护您的应用程序。 其中一个最快速扩张的BaaS平台,它由YC和Mozilla支持。 Supabase提供的许多产品中包括存储,实时数据库,功能和身份验证。 它节省了开发人员创建后端的麻烦,并包括其独特的安全措施。

在本教程中,您将将Supabase集成到SolidJS应用程序中,以处理用户身份验证。

前提条件

要遵循本教程,您将需要以下内容:

  • Node.js 已安装在您的计算机上,您可以通过在 How To Install Node.js上的教程来设置。
  • FirefoxChrome这样的网页浏览器。
  • Supabase 帐户。 请访问 Supabase 网站创建一个帐户。
  • (可选) 对 SolidJS 库的基本知识。 您可以查看 SolidJS 文档
  • (可选) 支持 JavaScript 语法突出的文本编辑器,如 [Visual Studio Code([INKL5])]或 [Atom](LINK6]

步骤 1 - 创建 SolidJS 项目

在本节中,您将创建 SolidJS 项目,安装所有必要的依赖并创建所需的组件。

您将使用 Vite 模板,该模板提供所需的 boilerplate 代码以在 JavaScript 或 TypeScript 中创建 SolidJS 应用程序。

打开新的终端窗口,创建一个新目录,将用于本教程,并移动到那里:

1mkdir auth
2    cd auth

本教程的目录被称为auth,但您可以随意命名它。

接下来,执行以下命令「npx degit」来将模板从「solid/js/templates/js」存储库克隆到您的项目目录:

1npx degit solidjs/templates/js solid-auth

您的应用程序的任何其他名称都可以用来代替固态

<$>[注] 注: TypeScript是JavaScript,具有类型特定的语法。基于JavaScript,TypeScript是一个强大的编程语言,在任何尺寸都提供更好的工具。它支持类、接口和可选的静态编写。此外,它还为JSX提供改进的代码完成和IntliSense。如果您喜欢使用TypeScript,请执行以下命令:

1npx degit solidjs/templates/ts solid-auth

您将收到对 /ts 模板的结果与对 /js 模板的结果相同。 对您而言, /ts/js 模板将产生相同的结果。

你会得到以下结果:

1[secondary_label Output]
2> cloned solidjs/templates#HEAD to solid-auth

此结果表明该模板已成功保存到您的计算机. 当该模板已克隆到您的项目文件夹时,请到那里安装该项目所需的依赖性:

1cd solid-auth
2npm install

要在 SolidJS 中配置用户身份验证,您需要三个额外的依赖性(supabase-js)(https://www.npmjs.com/package/@supabase/supabase-js),(https://www.npmjs.com/package/solid-supabase)和(https://www.npmjs.com/package/solid-router)。

Supabase-js 是一个与 JavaScript 非常相似的 Supabase 客户端。 Solid-Supabase 是一个基本的 Supabase.js 包装程序,为您提供作为一个固体链接的客户端访问。

Solid Router 是 SolidJS 的通用路由器,它无论在客户端还是服务器上进行渲染,都可运作,并结合了 React Router 和 Ember Router 原则。

要安装这些依赖,请使用以下命令:

1npm install @solidjs/router @supabase/supabase-js solid-supabase

接下来,通过运行以下命令启动开发服务器:

1npm run dev

输出将看起来像这样:

1[secondary_label Output]
2...
3  VITE v4.0.4 ready in 848 ms
4
5  ➜  Local:   http://localhost:3000/
6  ➜  Network: use --host to expose
7  ➜  press h to show help

您的应用程序现在运行在端口 3000. 若要访问 SolidJS 启动页面,请启动浏览器并输入以下 URL: http://localhost:3000/:

SolidJS startup page showing the logo and some text

<$>[注] **注: ** 端口转发可以用来在浏览器中测试应用程序,如果您在远程服务器上遵循教程。

在本地计算机上打开的其他终端中运行下列命令,因为开发服务器仍然活跃:

1ssh -L 3000:localhost:3000 your_non_root_user@your_server_ip

打开本地机器的网页浏览器,并在连接到服务器后转到http://localhost:3000。 在本教程的持续时间内,请将第二个终端打开。

接下来,您将为应用程序创建组件,以及所需的样式,即登录,注册仪表板组件。 在src目录中创建一个组件文件夹:

1mkdir src/components

然后添加一个新的Login.jsx文件:

1nano src/components/Login.jsx

createSignalA导入到新的Login.jsx文件中:

1[label src/components/Login.jsx]
2import { createSignal } from "solid-js";
3import { A } from "@solidjs/router";

然后包括下面的行来创建一个登录组件:

 1[label src/components/Login.jsx]
 2const Login = () => {
 3    const [email, setEmail] = createSignal(''); // email of the user
 4    const [password, setPassword] = createSignal(''); // password of the user
 5
 6    return (
 7        <div class="account-section">
 8            <form>
 9                <h3>Login</h3>
10                <label>Email</label>
11                <input type="email"
12                    onChange={(e) => setEmail(e.target.value)} />
13                <label>Password</label>
14                <input
15                    type="password"
16                    onChange={(e) => setPassword(e.target.value)}
17                />
18                <button type="submit">Login</button>
19                <span>
20                    Don't have an account? <A href="/register">Register here</A>
21                </span>
22            </form>
23        </div>
24    )
25}
26
27export default Login

信号固体中反应性的基石.当你改变一个信号的值时,所有依赖于它的一切无疑会更新,因为它们包含动态数据。

用于生成信号的参数是起始值,返回值是包含两个函数( gettersetter的数组)。 返回当前值的函数是第一个返回值,而不是值本身。

可以使用A组件创建指向路线的元素。

登录函数中,电子邮件密码是以空字符串(``)的初始值的输入器,而setEmailsetPassword是设置器。 现在,您创建了一个基本登录表格,包含一个标题,两个标签输入器和一个按钮。 您使用OnChange事件并将输入值设置在声明的信号上。

然后添加一个Register.jsx文件:

1nano src/components/Register.jsx

createSignal导入到Register.jsx文件中:

1[label src/components/Register.jsx]
2import { createSignal } from "solid-js";
3import { A } from "@solidjs/router";

然后嵌入以下行来创建一个注册组件:

 1[label src/components/Register.jsx]
 2const Register = () => {
 3
 4    const [email, setEmail] = createSignal(''); // email of the user
 5    const [password, setPassword] = createSignal(''); // password of the user
 6
 7    return (
 8        <div class="register-section">
 9            <form>
10                <h3>Register</h3>
11                <label>Email</label>
12                <input type="email"
13                    onChange={(e) => setEmail(e.target.value)} />
14                <label>Password</label>
15                <input
16                    type="password"
17                    onChange={(e) => setPassword(e.target.value)}
18                />
19                <button type="submit">Register</button>
20                <span>
21                    Already have an account? <A href="/login">Login here</A>
22                </span>
23            </form>
24        </div>
25    )
26}
27
28export default Register

这里使用的信号src/components/Login.jsx中的信号相同。 在此时,您创建了一个简单的注册表格,包含一个标题,两个标签输入和一个按钮。

然后添加一个Dashboard.jsx文件:

1nano src/components/Dashboard.jsx

createSignal导入到Dashboard.jsx文件中:

1[label src/components/Dashboard.jsx]
2import { createSignal } from "solid-js";

接下来,添加以下行来创建一个仪表板组件:

 1const Dashboard = () => {
 2    const [user, setUser] = createSignal({}); // user details
 3    return (
 4       <div class="dashboard-section">
 5            <div class="user-detail">
 6                <h3>Dashboard</h3>
 7                <h4>Welcome, User</h4>
 8                <button type="button" class="logout">Log out</button>
 9            </div>
10        </div>
11    )
12}
13
14export default Dashboard

仪表板组件包含标题标签和按钮中的标题和问候,然后创建一个信号,将保留当前用户的详细信息,并以空对象({})进行初始化。

现在在src/index.css中,添加在组件中使用的基本风格:

 1[label src/index.css]
 2* {
 3    box-sizing: border-box;
 4    margin: 0;
 5    padding: 0;
 6}
 7
 8body {
 9    background-color: rgb(229, 231, 235);
10}
11
12h3 {
13    font-size: 1.5rem;
14    font-weight: 900;
15    color: rgb(55, 65, 81);
16    text-align: center;
17}
18
19form {
20    padding: 48px;
21    margin-top: 2rem;
22    width: 370px;
23    height: 400px;
24    background-color: #fff;
25    border-radius: 4px;
26    box-shadow: 4px 4px 7px lightgray;
27}
28
29label {
30    text-transform: capitalize;
31    margin-top: 1.2rem;
32    margin-bottom: 0.3rem;
33    font-size: 0.8rem;
34    letter-spacing: 0.5px;
35    color: rgb(55, 65, 81);
36}
37
38input {
39    width: 100%;
40    line-height: 2rem;
41    background-color: rgb(229, 231, 235);
42    border: none;
43    padding: 0.375rem 0.75rem;
44    border-radius: 4px;
45    margin: 0.2rem 0 1rem;
46}
47
48button {
49    margin-top: 1.2rem;
50    margin-bottom: 0.5rem;
51    width: 100%;
52    height: 3rem;
53    font-size: 0.9rem;
54    font-weight: 700;
55    color: rgb(220, 229, 247);
56    background-color: rgb(37, 99, 235);
57    border-radius: 4px;
58    border: none;
59    cursor: pointer;
60}
61
62.account-section {
63    display: flex;
64    justify-content: center;
65    width: 100%;
66    margin-top: 1.4rem;
67}
68
69.dashboard-section {
70    display: flex;
71    justify-content: center;
72    margin-top: 100px;
73    width: 100%;
74}
75
76.user-detail {
77    text-align: center;
78    width: 370px;
79}
80
81.logout {
82    background-color: #dc3545;
83}
84
85.error {
86  color: #dc3545;
87  margin: 0.5rem 0;
88  display: block;
89}

CSS 文件位于 root 目录中,这意味着在所有组件中都有所写的样式,因此不需要将其导入到每个组件中。

Your login page now looks as below: A Login page showing page title, inputs and login button Similarly, the register appears as so: A Login page showing page title, inputs and register button The dashboard page is as shown: A Dashboard page showing page title, greeting and logout button You can now proceed to configure the routes for the application. Open the src/index.jsx file:

1nano src/index.jsx

输入路由器组件:

1[label src/index.jsx]
2import { Router } from "@solidjs/router";

接下来,将您的根组件包装到路由器组件中:

1[label src/index.jsx]
2render(() =>
3        <Router>
4            <App />
5       </Router>
6, document.getElementById('root'));

这为我们提供了一个背景,使我们能够在应用程序中的任何地方显示路线。

现在,打开src/App.jsx文件:

1nano src/App.jsx

输入路线,路线,然后分别输入登录,注册仪表板组件,然后为您的应用程序配置路线:

 1[label src/App.jsx]
 2import { Routes, Route } from "@solidjs/router"
 3import Register from './components/Register';
 4import Login from './components/Login';
 5import Dashboard from './components/Dashboard';
 6
 7function App() {
 8  return (
 9    <>
10      <Routes>
11        <Route path="/" component={Dashboard}/>
12        <Route path="/login" component={Login}/>
13        <Route path="register" component={Register} />
14      </Routes>
15    </>
16  );
17}
18
19export default App;

然后,在添加路线时,使用路线组件来定义路径,当用户导航到该路径时要渲染的元素或组件,并直接导航路线。

步骤 2 - 设置 Supabase

要開始,請前往您的瀏覽器上的 Supabase 網站。然後,在导航栏的右邊,點一下「開始您的項目」按鈕;您被指向登入頁面。 要登入或登入,請按需要輸入您的資訊。 一旦登入,您將被帶到項目頁面。

从这里创建一个项目,点击新项目按钮,您需要在创建新项目页面上输入项目的具体信息,如下所示:

A Supabase project creation page with input for necessary parameters

一旦完成,您将被带到创建的项目的仪表板。 从侧面菜单中选择 身份验证,然后选择 提供商以启用所需的身份验证方法。

A Supasbase authentication page showing all the available auth providers As a convention, the user must first validate their email address before logging in, but in this tutorial that function was disabled. To integrate Supabase into your Solid app, you need to add the Supabase project URL and API key to your app. On your project dashboard side menu, navigate to settings then select API to see your project URL and keys as below:

A Supabase API settings page showing project URL and API keys Now, proceed to add Supabase to your SolidJS app.

步骤 3 - 将 Supabase 集成到 SolidJS

要在 SolidJS 中配置 Supabase,请复制 Supabase URL 和 Supabase 控制台上的项目设置中的键。 在应用程序的根部创建一个环境文件 .env 文件以将此 URL 和键存储为环境变量:

1nano .env

继续以这样的方式在变量中添加值:

1[label .env]
2VITE_SUPABASE_URL=your supabase url
3VITE_SUPABASE_KEY=your supabase key

<$>[注] 注: 环境变量是具有动态名称的值,可以修改计算机上活跃过程的行为方式。 任何数量的环境变量都可以同时创建并使其可用;每个环境变量都由一个名称/值对组成。

.env 文件的环境变量由 Vite使用 dotenv加载。

然后,在应用程序的根部,设置Supabase 提供商,以包装整个应用程序,并将.env的细节作为参数。

打开src/index.jsx文件并添加以下代码:

 1[label src/index.js]
 2import { render } from 'solid-js/web';
 3import { Router } from "@solidjs/router";
 4import { createClient } from '@supabase/supabase-js';
 5import { SupabaseProvider } from 'solid-supabase';
 6
 7import './index.css';
 8import App from './App';
 9
10const supabase = createClient(import.meta.env.VITE_SUPABASE_URL, import.meta.env.VITE_SUPABASE_KEY);
11
12render(() =>
13
14     <SupabaseProvider client={supabase}>
15        <Router>
16            <App />
17        </Router>
18     </SupabaseProvider> 
19
20, document.getElementById('root'));

首先,您从@supabase/supabase-jssolid-supabase中导入createClientSupabaseProvider。 然后,您创建一个恒定的supabase并使用createClient()方法启动一个新的 Supabase 客户端。

Supabase 客户端是可以访问 Supabase 功能的界面,它提供了与 Supabase 生态系统的所有组件最简单的通信方式。

然后利用SupabaseProvider作为包装器,并为 supabase 客户端提供您的凭据。

继续创建的组件,并连接适当的 Supabase 函数来设置身份验证。

src/components/Login.jsx文件中,先导入createSupabaseuseNavigate:

1[label src/components/Login.jsx]
2import { createSupabase } from 'solid-supabase';
3import { useNavigate, A } from "@solidjs/router";

然后用 supabase 身份验证方法更新登录组件:

 1[label src/components/Login.jsx]
 2import { createSignal } from "solid-js";
 3import { createSupabase } from 'solid-supabase';
 4import { useNavigate, A } from "@solidjs/router";
 5
 6const Login = () => {
 7 const supabase = createSupabase(); 
 8    const [email, setEmail] = createSignal(''); // email of the user
 9    const [password, setPassword] = createSignal(''); // password of the user
10 const navigate = useNavigate(); 
11
12    const loginUser = async (e) => {
13        e.preventDefault();
14        const { data, error } = await supabase.auth.signInWithPassword({
15            email: email(),
16            password: password(),
17        })
18        if (error) {
19            alert(error.message);
20            return;
21        }
22
23        if (data) {
24            navigate("/");
25        }
26    } 
27
28    return (
29        <div class="account-section">
30            <form onSubmit={(e) => loginUser(e)}>
31                <h3>Login</h3>
32                <label>Email</label>
33                <input type="email"
34                    onChange={(e) => setEmail(e.target.value)} />
35                <label>Password</label>
36                <input
37                    type="password"
38                    onChange={(e) => setPassword(e.target.value)}
39                />
40                <button type="submit">Login</button>
41                <span>
42                    Don't have an account? <A href="/register">Register here</A>
43                </span>
44            </form>
45        </div>
46    )
47}
48
49export default Login

createClient()方法被用来初始化一个新客户端并存储在一个恒定的supabase中。useNavigate()方法的实例被创建并传递到恒定的navigate中。useNavigate()方法采用路径移动到辅助对象中。loginUser是一个不同步的函数,它接受在登录表单提交后被召唤的事件(e)参数。preventDefault()方法阻止了表单的默认操作,这涉及在页面提交后更新。supabase.auth.signInWithPassword()方法接受输入的电子邮件密码的对象。它使用电子邮件和密码作为现有用户登录。

然后使用 destructuring assignment来获取数据错误的值。如果出现错误,则会发出错误消息并退出该函数。如果成功,则数据会返回用户详细信息并导航到仪表板。在启动登录表单中的OnSubmit事件时,会调用loginUser函数。

然后在src/components/Register.jsx文件中,先导入createSupabaseuseNavigate:

1[label src/components/Register.jsx]
2import { createSupabase } from 'solid-supabase';
3import { useNavigate, A } from "@solidjs/router";

然后使用 supabase 身份验证方法更新注册组件:

 1[label src/components/Register.jsx]
 2import { createSignal } from "solid-js";
 3import { createSupabase } from 'solid-supabase';
 4import { useNavigate, A } from "@solidjs/router";
 5
 6const Register = () => {
 7    const supabase = createSupabase();
 8    const [email, setEmail] = createSignal(''); // email of the user
 9    const [password, setPassword] = createSignal(''); // password of the user
10    const navigate = useNavigate();
11
12    const registerUser = async (e) => {
13        e.preventDefault();
14        const { data, error } = await supabase.auth.signUp({
15            email: email(),
16            password: password(),
17        })
18        if (error) {
19            alert(error.message);
20            return;
21        }
22
23        if (data) {
24            navigate("/");
25        }
26    } 
27
28    return (
29        <div class="account-section">
30            <form onSubmit={(e) => registerUser(e)}>
31                <h3>Register</h3>
32                <label>Email</label>
33                <input
34                    type="email"
35                    value={email()}
36                    onChange={(e) => setEmail(e.target.value)} />
37                <label>Password</label>
38                <input
39                    type="password"
40                    value={password()}
41                    onChange={(e) => setPassword(e.target.value)}
42                />
43                <button type="submit">Register</button>
44                <span>
45                    Already have an account? <A href="/login">Login here</A>
46                </span>
47            </form>
48        </div>
49    )
50}
51
52export default Register

使用createClient()方法创建一个新客户端,然后将其保存到supabase常数中。navigate常数将被引用到useNavigate()方法的新实例中。在提交注册表单时,被称为接受事件(e)参数的registerUser等同函数。表单的默认行为,其中包括提交后更新页面,被防止使用preventDefault()方法。supabase.auth.signUp()方法将emailpassword的对象取代。dataanderrorare`值随后通过破坏分配获得。如果出现错误,则显示错误消息,并且该函数终止。如果成功,则数据将用户的信息发送给您,并将您送

src/components/Dashboard.jsx文件中,导入createEffect,createSupabaseuseNavigate:

1[src/components/Dashboard.jsx]
2   import { createEffect, createSignal } from "solid-js";
3import { createSupabase } from 'solid-supabase';
4import { useNavigate } from "@solidjs/router";

效果是导致代码段的常规方法,有时被称为副作用,如果依赖改变,如手动修改 DOM,或对API进行调用。

接下来,将 supabase 身份验证方法添加到Dashboard组件中:

 1[src/components/Dashboard.jsx]
 2import { createEffect, createSignal } from "solid-js";
 3import { createSupabase } from 'solid-supabase';
 4import { useNavigate } from "@solidjs/router";
 5
 6const Dashboard = () => {
 7    const [user, setUser] = createSignal({});
 8const navigate = useNavigate();
 9const supabase = createSupabase();
10
11 createEffect(() => {
12        getLoggedUser();
13    })
14
15    const getLoggedUser = async () => {
16        const { data: { user } } = await supabase.auth.getUser();
17        setUser(user)
18        if(!user) {
19            navigate("/login", { replace: true });
20        }
21    }
22
23    const logOut = async () => {
24        let { error } = await supabase.auth.signOut();
25
26        if (error) {
27            alert(error.message);
28            return
29        }
30        setUser({})
31        navigate("/login", { replace: true });
32    }
33
34    return (
35        <div class="dashboard-section">
36            <div class="user-detail">
37                <h3>Dashboard</h3>
38                <h4>Welcome, {user() && user().email}</h4>
39
40                <button type="button" class="logout"  onClick={logOut}>Log out</button>
41            </div>
42        </div>
43    )
44}
45
46export default Dashboard

使用createClient()方法创建一个新客户端,然后将其保存到supabase常数中。

getLogged User'是一种Async函数,它利用supabase.auth.getUser ()'方法检索当前用户。 如果一个会话已经在进行中,它可以获得当前用户的信息. 它不使用本地会话,而是从数据库中获取用户对象. 返回的用户对象由setUser函数设定。 如果没有当前用户,则使用"navigate"功能来返回登录页面. 它使用一个附加参数,即取代'设定为真实'; 这改变了历史条目删除历史堆栈中的仪表盘路径. 一旦安装了 " Dashboard " 组件,便会使用这种方法,因为它被称作 " 创造效果 " 。 logOut 也是使用 supabase.auth. signOut () 方法登录登录用户的一种自动函数。 它会结束当前登录的用户浏览器会话并登出,从本地存储中删除所有数据. 如果发生错误,则显示消息并停止该函数。 " 用户 " 被设定为空对象, " navigate " 方法将重定向到登录页。 登录的用户电子邮件在 h4 标签中显示,而 logOut 功能则由登录按钮上的onClick事件所触发。 保存所有文件和测试以确保所有工作都很好.

结论

在本文中,您建立了一个使用用户身份验证的SolidJS应用程序,该应用程序使用Supabase作为后端。

请访问 SolidJS 文档以了解更多有关 SolidJS 功能的信息,查看 Supabase 文档以获取有关 Supabase 和其提供的众多功能的更多信息。

Published At
Categories with 技术
Tagged with
comments powered by Disqus