WEB

【Express.js + mongoDB】JWTによるユーザー認証

WEB
この記事は約5分で読めます。

バージョン

"dependencies": {
    "bcryptjs": "^2.4.3",
    "express": "^4.17.1",
    "jsonwebtoken": "^8.5.1",
    "mongoose": "^5.11.17",
  }

秘密鍵と有効期限の設定

設定ファイルに書きます。

.env

JWT_SECRET=somesecretkey
JWT_EXPIRED=30d

User スキーマ

emailpasswordのみのユーザーです。

const UserSchema = new mongoose.Schema({
  email: {
    type: String,
    unique: true,
    required: [true, "Please add an Email"],
    match: [
      /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/,
      "Please use a valid email address",
    ],
  },
  password: {
    type: String,
    required: [true, "Please add a password"],
    minlength: 6,
    select: false,
  },
});

JWTの生成

UserモデルにJWT生成メソッドを追加します。

  • Useridを元にトークンを生成します。
import jwt from "jsonwebtoken";

UserSchema.methods.getSignedJwtToken = function () {
  return jwt.sign(
    { id: this._id },
    process.env.JWT_SECRET,
    { expiresIn: process.env.JWT_EXPIRED }
  );
};

ユーザー登録成功時にJWTを返却

登録成功時に作成したUserのメソッドを呼び出します。

/**
 * @desc Register User
 * @route POST /api/v1/auth/register
 * @access Public
 */
export const register = async (req, res, next) => {
  const { email, password } = req.body;

  const user = await User.create({
    email,
    password,
  });

  // Token生成
  const token = user.getSignedJwtToken();

  res.status(200).json({ success: true, data: user, token });
};

ユーザーログイン成功時にJWTを返却

ログイン時も同様です。

/**
 * @desc Login User
 * @route POST /api/v1/auth/login
 * @access Public
 */
export const login = (req, res, next) => {
  const { email, password } = req.body;

  const user = User.findOne({ email }).select("+password");

  // Token生成
  const token = user.getSignedJwtToken();

  res.status(200).json({ success: true, token });
};

JWTを検証するミドルウェア

import jwt from "jsonwebtoken";

/**
 * トークンを検証するミドルウェア
 * Routesに差し込んで使用する
 * 有効なトークンを持っていない場合は401エラーを返す
 */
export const protect = (req, res, next) => {
  const { authorization } = req.headers;

  let token: string | undefined;

  // Bearer + Token を想定
  if (authorization && authorization.startsWith("Bearer")) {
    token = authorization.split(" ")[1];
  }

  if (!token) return next(new ErrorResponse("Not authorized to access this route", 401));

  try {
    // トークンの検証
    const decoded = jwt.verify(token, process.env.JWT_SECRET!) as DecodedJwt;
    req.user = await User.findById(decoded.id);

    next();
  } catch (err) {
    return next(new ErrorResponse("Not authorized to access this route", 401));
  }
});

ミドルウェアの使用

トークンが必要なルーティングに差し込んで使用します。

const router = express.Router();

router.use(protect);

router
  .route("/")
  .get(someProtectedRoute);