使用 Prisma 和 Planetscale 在 Astro 中设置身份验证

一段时间以来,我一直想为我的个人网站添加身份验证,以了解它在 Astro 中的工作原理。由于 Prisma 和 PlanetScale 已经在我的博客上
征求意见,我决定将我的帐户信息存储在 PlanetScale 中。 因为它只是用于我自己的帐户,并且我没有在我的数据库中存储任何其他敏感信息,所以我决定暂时以纯文本形式存储凭据。 我更改了我的 Prisma 模式以使其成为可能:


 

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>// schema.prisma

model Account {
  id Int @id @default(autoincrement())
  username String @unique
  password String
}
</code></span></span>

在代码中更新模型后,运行npx prisma db push会将更改传播到 PlanetScale,因此架构会在实际数据库中更新。

我使用一个现有的包@astro-auth来处理我网站上的所有身份验证。
为此,我需要向我的应用程序添加 2 个环境变量:(ASTROAUTH_URL托管我网站的 URL)和ASTROAUTH_SECRET(一个自选密钥)。

因为我将凭据存储在 PlanetScale 中,所以我需要使用 来CredentialProvider启用使用用户名和密码登录。
上还有许多其他提供程序可用@astro-auth,如果您有兴趣,请查看软件包。
设置它所需的代码@astro-auth如下所示:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// /pages/api/auth/[...astroauth].ts</span>

<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-name-color)">AstroAuth</span> <span style="color:var(--syntax-declaration-color)">from</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">@astro-auth/core</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">CredentialProvider</span> <span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-declaration-color)">from</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">@astro-auth/providers</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span>
<span style="color:var(--syntax-declaration-color)">import</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">prisma</span> <span style="color:var(--syntax-text-color)">}</span> <span style="color:var(--syntax-declaration-color)">from</span> <span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-string-color)">../../../lib/prisma</span><span style="color:var(--syntax-string-color)">'</span><span style="color:var(--syntax-text-color)">;</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">all</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">AstroAuth</span><span style="color:var(--syntax-text-color)">({</span>
  <span style="color:var(--syntax-name-color)">authProviders</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">[</span>
    <span style="color:var(--syntax-name-color)">CredentialProvider</span><span style="color:var(--syntax-text-color)">({</span>
      <span style="color:var(--syntax-name-color)">authorize</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">async</span> <span style="color:var(--syntax-name-color)">properties</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">account</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">await</span> <span style="color:var(--syntax-name-color)">prisma</span><span style="color:var(--syntax-text-color)">?.</span><span style="color:var(--syntax-name-color)">account</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">findFirst</span><span style="color:var(--syntax-text-color)">({</span>
          <span style="color:var(--syntax-name-color)">where</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">{</span>
            <span style="color:var(--syntax-name-color)">username</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">properties</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">username</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-name-color)">AND</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">{</span>
              <span style="color:var(--syntax-name-color)">password</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">properties</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">password</span><span style="color:var(--syntax-text-color)">,</span>
            <span style="color:var(--syntax-text-color)">},</span>
          <span style="color:var(--syntax-text-color)">},</span>
          <span style="color:var(--syntax-name-color)">select</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">{</span>
            <span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-declaration-color)">true</span><span style="color:var(--syntax-text-color)">,</span>
          <span style="color:var(--syntax-text-color)">},</span>
        <span style="color:var(--syntax-text-color)">});</span>
        <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">account</span><span style="color:var(--syntax-text-color)">?.</span><span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
          <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-name-color)">properties</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">username</span><span style="color:var(--syntax-text-color)">;</span>
        <span style="color:var(--syntax-text-color)">}</span>
        <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-declaration-color)">null</span><span style="color:var(--syntax-text-color)">;</span>
      <span style="color:var(--syntax-text-color)">},</span>
    <span style="color:var(--syntax-text-color)">}),</span>
  <span style="color:var(--syntax-text-color)">],</span>
<span style="color:var(--syntax-text-color)">});</span>
</code></span></span>

创建登录页面非常简单。
我刚刚创建了一个表单,在提交时调用了该signIn()方法@astro-auth,然后 BOOM:已登录!
登录页面的代码:

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>// /pages/login.astro

<html>
  <head>
    <title>Login</title>
    <script>
      import { signIn } from '@astro-auth/client';

      document.addEventListener('DOMContentLoaded', () => {
        document.querySelector('form')?.addEventListener('submit', async e => {
          e.preventDefault();
          const form = e.target;
          if (form) {
            const formData = new FormData(form as HTMLFormElement);
            const data = Object.fromEntries(formData);
            await signIn({
              provider: 'credential',
              login: data,
            });
            window.location.href = '/';
          }
        });
      });
    </script>
  </head>
  <body>
    <form>
      <label for="username">Name</label>
      <input type="text" name="username" />

      <label for="password">Password</label>
      <input type="password" name="password" />

      <input type="submit" value="Submit" />
    </form>
  </body>
</html>
</code></span></span>

提交表单后,用户登录并被重定向到主页。使用身份验证保护页面很容易,只需使用来自的函数
检查登录用户即可。 这是我使用此检查的页面示例:getUser()@astro-auth

 

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code>// /pages/comment-overview.astro

---
import { getUser } from '@astro-auth/core';
import Layout from '../layouts/Layout.astro';
import { prisma } from '../lib/prisma';
import CommentsOverviewWrapper from '../components/CommentOverviewWrapper';
const user = getUser({ client: Astro });
if (!user) {
  return Astro.redirect('/', 307);
}
const commentsWithPost = await prisma?.comment.findMany({
  include: {
    post: {
      select: {
        url: true,
      },
    },
  },
});
---

<Layout
  description="Overview of comments"
  title="Thomas Ledoux | Comment overview"
>
  <CommentsOverviewWrapper commentsWithPost={commentsWithPost} client:load />
</Layout>
</code></span></span>

如果用户未登录,用户将被重定向到带有 307状态代码的主页。
我还有一个 API 路由来删除我的博客文章上的评论,我想将其隔离,以便只有经过身份验证的用户才能使用此 API。也可以为此
使用getUser()函数 from ,但这次我们将传递而不是对象。 使用此代码的示例:@astro-authrequestAstro

 

<span style="color:var(--syntax-text-color)"><span style="color:var(--syntax-text-color)"><code><span style="color:var(--syntax-comment-color)">// /pages/api/comments.ts</span>

<span style="color:var(--syntax-declaration-color)">export</span> <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">del</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">APIRoute</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">async</span> <span style="color:var(--syntax-text-color)">({</span> <span style="color:var(--syntax-name-color)">request</span> <span style="color:var(--syntax-text-color)">})</span> <span style="color:var(--syntax-error-color)">=></span> <span style="color:var(--syntax-text-color)">{</span>
  <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">user</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-name-color)">getUser</span><span style="color:var(--syntax-text-color)">({</span> <span style="color:var(--syntax-name-color)">server</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">request</span> <span style="color:var(--syntax-text-color)">});</span>
  <span style="color:var(--syntax-declaration-color)">if</span> <span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-name-color)">user</span><span style="color:var(--syntax-text-color)">)</span> <span style="color:var(--syntax-text-color)">{</span>
    <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">body</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">await</span> <span style="color:var(--syntax-name-color)">request</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">json</span><span style="color:var(--syntax-text-color)">();</span>
    <span style="color:var(--syntax-declaration-color)">const</span> <span style="color:var(--syntax-name-color)">deleteComment</span> <span style="color:var(--syntax-error-color)">=</span> <span style="color:var(--syntax-declaration-color)">await</span> <span style="color:var(--syntax-name-color)">prisma</span><span style="color:var(--syntax-text-color)">?.</span><span style="color:var(--syntax-name-color)">comment</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-declaration-color)">delete</span><span style="color:var(--syntax-text-color)">({</span>
      <span style="color:var(--syntax-name-color)">where</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-text-color)">{</span>
        <span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-name-color)">body</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-text-color)">,</span>
      <span style="color:var(--syntax-text-color)">},</span>
    <span style="color:var(--syntax-text-color)">});</span>
    <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-declaration-color)">new</span> <span style="color:var(--syntax-name-color)">Response</span><span style="color:var(--syntax-text-color)">(</span>
      <span style="color:var(--syntax-name-color)">JSON</span><span style="color:var(--syntax-text-color)">.</span><span style="color:var(--syntax-name-color)">stringify</span><span style="color:var(--syntax-text-color)">({</span>
        <span style="color:var(--syntax-name-color)">message</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-string-color)">`Comment with id </span><span style="color:var(--syntax-text-color)">${</span><span style="color:var(--syntax-name-color)">deleteComment</span><span style="color:var(--syntax-text-color)">?.</span><span style="color:var(--syntax-name-color)">id</span><span style="color:var(--syntax-text-color)">}</span><span style="color:var(--syntax-string-color)"> deleted`</span><span style="color:var(--syntax-text-color)">,</span>
      <span style="color:var(--syntax-text-color)">}),</span>
      <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">status</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">200</span> <span style="color:var(--syntax-text-color)">}</span>
    <span style="color:var(--syntax-text-color)">);</span>
  <span style="color:var(--syntax-text-color)">}</span>
  <span style="color:var(--syntax-declaration-color)">return</span> <span style="color:var(--syntax-declaration-color)">new</span> <span style="color:var(--syntax-name-color)">Response</span><span style="color:var(--syntax-text-color)">(</span><span style="color:var(--syntax-declaration-color)">null</span><span style="color:var(--syntax-text-color)">,</span> <span style="color:var(--syntax-text-color)">{</span> <span style="color:var(--syntax-name-color)">status</span><span style="color:var(--syntax-text-color)">:</span> <span style="color:var(--syntax-literal-color)">403</span> <span style="color:var(--syntax-text-color)">});</span>
<span style="color:var(--syntax-text-color)">};</span>
</code></span></span>

所以当用户未通过身份验证时,将返回 403 响应。

希望这对您有所帮助!源代码可以一如既往地在我的 Github
上找到。

猜你喜欢

转载自blog.csdn.net/jascl/article/details/131304357