NextAuth.jsでPrismaを使って認証情報をDBに格納する(MySQL)
前回はDBレスでログインとセッション管理を確認しました。公式のサポート内でDBを利用したユーザーとセッション管理も提供されているため、そちらを試してみます。DBはたまたま動かしていたMySQLがあったのでそれを使います。
いくつか選択肢がありますがシンプルなORMのPrismaを利用します
パッケージのインストール
npm install @prisma/client @auth/prisma-adapter
npm install prisma --save-dev
Prismaのクライアントとアダプタをインストールします。npmのインストールコマンドでは公式のレジストリやgithubからパッケージを取得できるとのこと。githubからパッケージを取る場合はパッケージ名を Org/repository と指定するらしい。今回prismaのパッケージはnpmのレジストリから取っているのでgithubと間違えないようにパッケージ名の頭に@を付けていると認識しました。
アダプタを追加
現状のソースコードに追加していきます
import NextAuth, { NextAuthOptions } from "next-auth"
import GoogleProvider from "next-auth/providers/google"
import { PrismaAdapter } from "@auth/prisma-adapter";
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
export const authOptions: NextAuthOptions = {
adapter: PrismaAdapter(prisma),
providers: [
GoogleProvider({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
}),
]
}
export default NextAuth(authOptions)
マイグレーションを実行
設定ファイルを追加する
datasource db {
provider = "mysql"
url = "mysql://USER:PASSWORD@HOST:PORT/DATABASE"
}
generator client {
provider = "prisma-client-js"
previewFeatures = ["referentialActions"] // You won't need this in Prisma 3.X or higher.
}
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String? @db.Text
access_token String? @db.Text
expires_at Int?
token_type String?
scope String?
id_token String? @db.Text
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
}
model Session {
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
accounts Account[]
sessions Session[]
}
model VerificationToken {
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
}
マイグレーションのコマンドを実行したがエラーが起きた
$ npx prisma migrate dev
Error: P3014
Prisma Migrate could not create the shadow database. Please make sure the database user has permission to create databases. Read more about the shadow database (and workarounds) at https://pris.ly/d/migrate-shadow
Original error: Error code: P1010
User `itodoap` was denied access on the database `itodo`
シャドーデータベースが作成できない、という内容のエラーだった。URL(https://pris.ly/d/migrate-shadow)を確認して、MySQLだと以下の権限が必要なので付与して再度試す。
Database user must have CREATE, ALTER, DROP, REFERENCES ON *.* privileges
テーブルが作成できた
$ show databases;
+---------------------------------------------------------------+
| Database |
+---------------------------------------------------------------+
| information_schema |
| itodo |
| mysql |
| performance_schema |
| prisma_migrate_shadow_db_83ce692f-b250-47db-89b2-a3c9b34a5e99 |
| prisma_migrate_shadow_db_bcbf5865-596a-4183-a890-e5e41073874b |
| sys |
+---------------------------------------------------------------+
7 rows in set (0.0053 sec)
$ use itodo
$ show tables;
+--------------------+
| Tables_in_itodo |
+--------------------+
| Account |
| Session |
| User |
| VerificationToken |
| _prisma_migrations |
+--------------------+
5 rows in set (0.0055 sec)
クライアントの作成
npx prisma generate
準備できたので画面を動かす
$ npm run dev
画面上は前回同様、問題なくログインできました。
DBを確認したところアカウント情報やセッション情報が想定通りテーブルに書きこめていました。一部抜粋。
select id, provider from Account;
+---------------------------+----------+
| id | provider |
+---------------------------+----------+
| clmbnk6ke0002m54cmy7acom6 | google |
+---------------------------+----------+
$ select count(*) from Session;
+----------+
| count(*) |
+----------+
| 1 |
+----------+
認証とセッション管理はNextAuth.jsに任せることで想定通りに動き、DBでのアカウントの管理にも利用できました。このように実装が難しく、脆弱性があると影響が大きい根幹の部分を、ISCライセンスで一括利用できる。。大変な時代になったと改めて感じました。
WEBサービスであれば認証機能などに割いていた時間を、ユーザーに提供するビジネスロジック部分に割けるようになっているため、生産性を上げたり、工期短縮が可能になったと感じています。
Discussion