1
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.

B2BエンジニアがT3 Stackに入門してみたAdvent Calendar 2022

Day 5

t3-stack入門 (4) NextAuth.jsでEmail/Passwordでログインできるようにする

Last updated at Posted at 2022-12-05

B2Bエンジニアにソーシャルログインなんて必要ありません(そもそもインターネットに出れないので使えません)。
NextAuth.jsでソーシャルログインをやめEmail/Passwordでログインできるように変更します。

ハッシュ化するパッケージを導入する

npm install bcrypt @types/bcrypt

パスワードカラムを追加&初期データを設定する

prisma/schema.prismaのUserモデルにパスワード用のカラムを追加します。

model User {
  id            String    @id @default(cuid())
  name          String?
  email         String?   @unique
  emailVerified DateTime?
+  crypted_password String?
  image         String?
  accounts      Account[]
  sessions      Session[]
}

このままだとだれもログインできないので初期ユーザを追加するprisma/seed.tsを作成します。

import { PrismaClient } from "@prisma/client";
import bcrypt from "bcrypt";
const prisma = new PrismaClient();

async function main() {
  prisma.$connect();
  const saltRounds = 10;
  const password = "test";
  const hashedPassword = await bcrypt.hash(password, saltRounds);
  const testUser = await prisma.user.upsert({
    where: { email: "test@test.com" },
    update: {},
    create: {
      id: "clbopauhz0000umekzyiiw4ww",
      email: "test@test.com",
      name: "テストユーザ",
      crypted_password: hashedPassword,
    },
  });

  const testUser2 = await prisma.user.upsert({
    where: { email: "test2@test.com" },
    update: {},
    create: {
      id: "clbopauja0002umeko9x3bc63",
      email: "test2@test.com",
      name: "テストユーザ2",
      crypted_password: hashedPassword,
    },
  });
  console.log({ testUser, testUser2 });
}
main()
  .then(() => {
    console.log("finished");
  })
  .finally(() => {
    prisma.$disconnect();
  });

ts-nodeをインストールしてseed.tsを実行します。そのままだと実行できずオプションが必要でした。

~/t3-todo-example$ ts-node --compiler-options '{"module":"CommonJS"}' prisma/seed.ts
{
  testUser: {
    id: 'clbopauhz0000umekzyiiw4ww',
    name: 'テストユーザ',
    email: 'test@test.com',
    emailVerified: null,
    crypted_password: '$2b$10$4JHMU.D4Xd4z.czfIWyVsOfTZkErxb0bVZFYK8puDJKD/cH4VunhO',
    image: null
  },
  testUser2: {
    id: 'clbopauja0002umeko9x3bc63',
    name: 'テストユーザ2',
    email: 'test2@test.com',
    emailVerified: null,
    crypted_password: '$2b$10$4JHMU.D4Xd4z.czfIWyVsOfTZkErxb0bVZFYK8puDJKD/cH4VunhO',
    image: null
  }
}
finished

CredentialProviderを設定する

src/pages/api/auth/[...nextauth].tsをCredentialProviderを利用するように変更します

import NextAuth, { type NextAuthOptions } from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import bcrypt from "bcrypt";

import { env } from "../../../env/server.mjs";
import { prisma } from "../../../server/db/client";

export const authOptions: NextAuthOptions = {
  providers: [
    CredentialsProvider({
      // サインインフォームに表示する名前 (例: "Sign in with...")
      name: "E-mail/Password",
      credentials: {
        email: {
          label: "E-mail",
          type: "email",
          placeholder: "E-mail",
        },
        password: { label: "パスワード", type: "password" },
      },
      async authorize(credentials, req) {
        const email = credentials?.email;
        const password = credentials?.password || "";
        const user = await prisma.user.findUnique({ where: { email } });
        if (user == null) {
          return null;
        }
        if (bcrypt.compareSync(password, user.crypted_password || "")) {
          const { crypted_password, emailVerified, ...user2 } = user;
          return user2;
        } else {
          return null;
        }
      },
    }),
  ],
};

export default NextAuth(authOptions);

これでEmail/Passwordでログインできるようになりました。
signin_credential.png

ただ、なぜか adapter: PrismaAdapter(prisma)を削除しないと、ログインは成功するのですがSessionが取得できなくなってしまいました。
また、adapterを設定しない場合、いったいどこにSession情報が保存されているんでしょうか。メモリに保存されているのかなと思ったけどdevサーバを再起動してみてもSessionは引き継がれているみたいです。うーん、謎。

adapterを設定しない場合、どこにSession情報が保存されている?

NextAuthOptionsのjwtプロパティに答えが書いてありました。

/**
     * JSON Web Tokens are enabled by default if you have not specified an adapter.
     * JSON Web Tokens are encrypted (JWE) by default. We recommend you keep this behaviour.
     * * **Default value**: See the documentation page
     * * **Required**: *No*
     *
     * [Documentation](https://next-auth.js.org/configuration/options#jwt)
     */

ということで、adapterを設定しない場合JWTでセッション情報が保存されるみたいです。
CredentialsProviderとPrismaAdapterの組み合わせでセッションが有効にならない理由は謎ですが、JWTでセッションが有効になってるなら無理にDBにセッション情報を保存する必要はないのでそのままにしておきます。

ここまでの変更は以下の通りです。

追記

これでOだと思っていたのですが、session.user.idにidが設定されていませんでした。

をご覧ください。

1
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
1
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?