0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Next.js】Auth.js・Prisma・MailHog・Dockerを用いたメールログイン機能の実装

Posted at

はじめに

今回は、Next.jsとAuth.jsを用いたメールログイン機能を実装したので、そちらを記事にしていこうと思います。

認証方法

認証方法はマジックリンクを用いています。
マジックリンクは、ログイン時に入力したメールアドレス宛にログイン用のリンクが届き、リンクからログインするという認証方法です。

必要なライブラリの導入

公式を参照し、以下を導入します。

  • next-auth
  • prisma
  • @prisma/client
  • @auth/prisma-adapter
yarn add next-auth @prisma/client @auth/prisma-adapter
yarn add prisma --dev

認証プロバイダーの実装

[..nextauth].tsを作成し、Providerを以下のように作成します。

[...nextauth].ts
import { PrismaAdapter } from '@auth/prisma-adapter'
import NextAuth from 'next-auth'
import EmailProvider from 'next-auth/providers/email'

import { prisma } from '@/libs/prisma'

const EMAIL_SERVER = process.env.EMAIL_SERVER
const EMAIL_FROM = process.env.EMAIL_FROM
const NEXTAUTH_SECRET = process.env.NEXTAUTH_SECRET

if (!EMAIL_SERVER || !EMAIL_FROM || !NEXTAUTH_SECRET) {
  throw new Error('EMAIL_SERVER, EMAIL_FROM, or NEXTAUTH_SECRET not found.')
}

export default NextAuth({
  adapter: PrismaAdapter(prisma),
  providers: [
    EmailProvider({
      server: EMAIL_SERVER,
      from: EMAIL_FROM,
    }),
  ],
  secret: NEXTAUTH_SECRET,
})

記述はほとんど公式と同じようになっています。
Prismaを使用するので、adapterにPrisamAdapterを使用し、メール認証をするためEmailProviderを使用しています。
そのほかの認証を追加する場合、providersに追加していく形になります。
プロバイダーの実装は以上となります。

API Routerについて補足

ちなみに、Next.jsではAPI Routeといってapiディレクトリ以下にAPIのエンドポイントを作成することができます。例えば、デフォルトではhello.tsというファイルがありますが、こちらには、http://localhost:3000/helloとすることでアクセスできます。

そのため[..nextauth].tsとすると、/auth/[...nextauth]となるため、/auth/aでも/auth/bでもアクセスできますし、/auth/a/b/auth/a/b/cでもアクセスできます。要するに、ネストしたようなパスも全て、[ファイル名].tsでキャッチするということです。

Auth.jsではGoogle認証やTwitter認証などもあり、それをauthディレクトリ以下で管理するため、一元化するため(/auth/google・/auth/twitterなどをまとめて管理するため)、上記のようなファイル形式としています。

prismaクライアントの実装

src/libsディレクトリ以下に作成していきます。

prisma.ts
import { PrismaClient } from '@prisma/client'

const globalForPrisma = global as unknown as { prisma: PrismaClient }

export const prisma =
  globalForPrisma.prisma ||
  new PrismaClient({
    log: ['query'],
  })

if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma

公式とは少し記述が違いますが、このようにすることで正しく動作します。

DB・MailHogの環境構築 with Docker

続いて、PrismaでのDB環境やMailHogを使用できるようにDockerでコンテナを作成していきます。

docker-compose.yaml
version: '3.9'
services:
  db:
    image: mysql:8.0
    ports:
      - 3306:3306
    volumes:
      - mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_DATABASE=nextjs-prisma-graphql-codegen-dev
  mailhog:
    image: mailhog/mailhog
    ports:
      - 8025:8025
      - 1025:1025
volumes:
  mysql:

私の場合、MySQLを使用していますが、お好きなDBを使用してください。
Prismaのデフォルトがpostgresなので、postgresの方が構築は容易かもしれません。
(MySQLでの構築について記事にしているので、そちれも参照してみてください)

【Next.js】PrismaでMySQLローカル環境をDocker構築する方法

またmailhogについても環境を構築するようにしています。
http://localhost:8025でアクセスできるようにしています。

次のコマンドを実行し、.envを作成します。

npx prisma init 

以下のようなファイルが作成されます。

.env
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema

# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings

DATABASE_URL="mysql://root:パスワード@localhost:3306/DB名"

ここでコンテナによるローカル環境構築を行います。

docker-compose up

環境変数追加

正常に立ち上がったら環境変数を追加していきます。
以下のようになります。

.env
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema

# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings

DATABASE_URL="mysql://root:password@localhost:3306/nextjs-prisma-graphql-codegen-dev"
EMAIL_SERVER="smtp://user:password@localhost:1025"
EMAIL_FROM="noreply@example.com"
NEXTAUTH_SECRET="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
NEXTAUTH_URL="http://localhost:3000/"

NEXTAUTH_SECRETですが、以下のコマンドでシークレット情報を取得し、コピーする必要があります。

openssl rand -base64 32

これで出力されたシークレットを貼り付けてください。

最後にPrismaのマイグレーションファイル(テーブル)を作成していきます。
以下を実行します。

npx prisma migrate dev

正常通りいけば、prisma/migrationsにファイルが作成されます。

フロントエンド実装

次に簡易的ではありますが、フロント部分を作成します。
まず、pagesディレクトリにある_app.tsxを改修します。

_app.tsx
import '@/styles/globals.css'

import type { AppProps } from 'next/app'
import { SessionProvider } from 'next-auth/react'

export default function App({ Component, pageProps }: AppProps) {
  return (
    <SessionProvider session={pageProps.session}>
      <Component {...pageProps} />
    </SessionProvider>
  )
}

ここでは、SessionProviderにより、セッションを扱えるようにしています。

次に、index.tsxも手を加えます。

index.tsx
import { signIn, signOut, useSession } from 'next-auth/react'

const Home = () => {
  const { data: session } = useSession()

  if (session) {
    return (
      <>
        Signed in as {session.user?.email} <br />
        <button onClick={() => signOut()}>Sign out</button>
      </>
    )
  }

  return (
    <>
      Not signed in <br />
      <button onClick={() => signIn()}>Sign in</button>
    </>
  )
}

export default Home

こちらはAuth.jsの公式のまんまの記述になります。
useSessioonでセッションを扱え、セッション情報があれば、user情報を表示するようになっています。

画面動作確認

実際の画面の動きは以下です。
スクリーンショット 2023-06-28 8.32.21.png
メールアドレスを入力し、ボタンを押すと、MailHogにメール通知が行きます。
MailHogにはhttp://localhost:8025でアクセスできます。
76b0c128e022edd608fa68379e232fd1_AdobeExpress.gif

さらに、以下のコマンドでPrismaスキーマのデータを確認できます。

npx prisma studio

http://localhost:5555でPrismaStudioを見ることができます。
Userスキーマですが、以下のようにデータが入っているのがわかると思います。
スクリーンショット 2023-06-28 8.46.50.png

以上で、実装は終了です。
参考にしてみてください。

参考文献

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?