Expressで認証周りについて調べたときの備忘録。
Passport.jsという便利なのもあるけど、
パスワードのハッシュ化やJWTトークン周りは自前で用意する必要がある感じ。
(ソーシャルは不要なので、使わない形の例)
- パスワードのハッシュ化はBcrypt or Crypto
- JWTトークンはjsonwebtoken
※この例のCryptoのpbkdf2よりもBcryptのほうがアルゴリズムが強固なので、Bcryptのほうがよい
使い方
まずはインストール。CryptoはNode.jsのライブラリなので、インストール不要。
$ npm i jsonwebtoken
使い方はこんな感じ。
import { Request, Response, Router } from "express"; import crypto from "crypto"; import jwt from "jsonwebtoken"; import { User } from "./model"; // DBなどにアクセスするモデル export type JwtPayload = { uid: number; }; const JWT_SECRET_KEY = "YOUR_SECRET_KEY"; // ログイン: email/passwordを受け取り、JWTを返す export async function login(req: Request, res: Response) { const { email, password } = req.body; // ユーザの取得 const user = await User.findByEmail(email); if (!user) throw new Error("user not found"); // ハッシュ化したパスワードを取得 const salt = "...your_salt..."; const iterations = 100000; const hashKey = crypto.pbkdf2Sync(password, salt, iterations, 64, "sha512"); const hashedPass = hash.toString("base64"); if (user.password != hash) throw new Error("user not found"); // JWTの生成 const payload: JwtPayload = { uid: user.id, }; const option = {}; const token = jwt.sign(payload, JWT_SECRET_KEY, option); return res.json({ token: token }).end(); } // ログインユーザの情報取得 export async function me(req: Request, res: Response) { // JWTの検証: トークンからuidの取得 const auth = req.headers.authorization?.split(" "); if (!auth || auth[0] != "JWT" || !auth[1]) throw new Error("JWT not found"); const payload = jwt.verify(token, SECRET_KEY) as JwtPayload; if (!payload) throw new Error("user not found"); // ユーザの取得 const user = await User.findByUid(payload.uid); if (!user) throw new Error("user not found"); return res.json({ user: { uid: user.id, username: user.username } }); }
Bcryptでのハッシュ化
まずはインストール。ライブラリはこれ。
・ kelektiv/node.bcrypt.js: bcrypt for NodeJs
$ npm i bcrypt
使い方はこんな感じ。
import bcrypt from "bcrypt"; // ハッシュ化したパスワードの取得 const password = "...YOUR_PASSOWRD..."; const saltRounds = 10; const hashedPassword = bcrypt.hashSync(password, saltRounds); // 検証 const plaintextPassword = "...YOUR_PASSOWRD..."; const user = "..."; const match:boolean = bcrypt.compareSync(plaintextPassword, user.passwordHash);
以上!!