passport, passport-local, Prismaを用いた認証例

覚えておきたい

2025/02/24 -最終更新日:2025/03/04

Prisma↓

prisma.schema
model User { 
 id String @id @default(uuid()) 
 email String @unique 
 password String 
 name String? 
 createdAt DateTime @default(now()) 
 updatedAt DateTime @updatedAt 
}

しっかりマイグレーションして、passportの基礎設定。

認証はユニークな「email」と「パスワード」で行います。

app.ts
import passport from "passport";
import { Strategy as LocalStrategy } from "passport-local";
import bcrypt from "bcrypt";
import { PrismaClient, User } from "@prisma/client"; // Userをtypeとして使う

....

app.use(passport.initialize());
app.use(passport.session()); // これは必ずsession設定の後にする

passport.use(
 new LocalStrategy(
  { usernameField: "email" },
  async (email, password, done) => {
   try {
    const user = await prisma.user.findUnique({ where: { email } });

    if (!user)
     return done(null, false, { message: "ユーザーが見つかりません" });

    const isMatch = await bcrypt.compare(password, user.password);
       if (!isMatch)
        return done(null, false, { message: "パスワードが違います" });

       return done(null, user);
      } catch (error) {
     return done(error);
    }
   }
  )
 );

passport.serializeUser((user, done) => {
 try {
  done(null, (user as User).id);
 } catch (error) {
  done(error)
 }
});

passport.deserializeUser(async (id: string, done) => {
 try {
  const user = await prisma.user.findUnique({ where: { id } });
  if (!user) return done(null, false);
  done(null, user);
 } catch (error) {
  done(error)
 }
});

登録

.post("/register",
async (req: Request, res: Response) => {
 const { name, email, password } = req.body;
 const hashedPassword = await bcrypt.hash(password, 10);
 try {
  await prisma.user.create({
   data: { email, password: hashedPassword, name },
  });
  req.flash("success", "ユーザー登録完了");
  res.redirect("/homeとか");
 } catch (error: any) {
  req.flash("error", error.message);
  res.redirect("/register"); 
 } 
});

ログイン

passport.authenticate()をミドルウェアとして設定

.post("/login",
 passport.authenticate("local", {
  // flashなど設定していないのであれば 
  // successRedirect: '/' 
  failureFlash: true,
  failureRedirect: "/login",
 }),
 (req: Request, res: Response) => {
  req.flash("success", "おかえり");
  res.redirect("/homeとか");
 }
);

passportが勝手にreq.isAuthenticated()を作ってくれてる。

認証できていればreq.isAuthenticated()がtrueを返す。

のでこれを利用してログインしてなければできない処理とかを登録する。

ログアウトしたい場合、req.logout()とする。

req.userにデシリアライズされたuser情報が入っている。

参考githubのpush履歴:https://github.com/Musasi914/express-ts-test/commit/d06fd89e23c775e65b927d17b1ca1d2cea6e4cff

以上b