トークンを検証して、トークンを保持しているユーザーのみ、book のデータを表示させます。

コードは、前回までのコードを使用します。

index.js

const express = require("express")
const bodyParser = require("body-parser")
const mongoose = require("mongoose")

const authRoutes = require("./routes/auth")
const bookRoutes = require("./routes/book")

const app = express()

app.use(bodyParser.json())

app.use((req, res, next) => {
  res.setHeader("Access-Control-Allow-Origin", "*")
  res.setHeader(
    "Access-Control-Allow-Methods",
    "GET, POST, PUT, PATCH, DELETE, OPTION"
  )
  res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization")
  next()
})

app.use("/auth", authRoutes)
app.use("/book", bookRoutes)

mongoose
  .connect(
    "mongodb+srv://Nao:abcdefgh.q1atv.mongodb.net/myFirstDatabase?retryWrites=true&w=majority"
  )
  .then(() => {
    app.listen(8000)
    console.log("Server is running ...")
  })
  .catch(err => {
    console.log(err)
    throw err
  })

routes/auth.js

const express = require("express")
const { body } = require("express-validator")

const authController = require("../controllers/auth")

const router = express.Router()

router.post(
  "/sign_up",
  [
    body("email")
      .isEmail()
      .withMessage("メールアドレスを入力してください")
      .normalizeEmail(),
    body("password").trim().isLength({ min: 4 }),
  ],
  authController.signUp
)

router.post("/login", authController.login)

module.exports = router

routes/book.js

const express = require("express")
const { body } = require("express-validator")

const bookController = require("../controllers/book")

const router = express.Router()

router.get("/get", bookController.getBook)

router.post(
  "/post",
  body("content").trim().isLength({ min: 4 }),
  bookController.postBook
)

module.exports = router

model/user.js

const mongoose = require("mongoose")
const Schema = mongoose.Schema

const userShema = new Schema({
  email: String,
  password: String,
})

module.exports = mongoose.model("User", userShema)

model/book.js

const mongoose = require("mongoose")
const Schema = mongoose.Schema

const bookShema = new Schema({
  title: String,
  content: String,
})

module.exports = mongoose.model("Book", bookShema)

controllers/auth.js

const User = require("../model/user")

const { validationResult } = require("express-validator")

const bcrypt = require("bcrypt")

const jwt = require("jsonwebtoken")

exports.signUp = (req, res, next) => {
  const errors = validationResult(req)
  if (!errors.isEmpty()) {
    return res
      .status(400)
      .json({ message: "validation errors", errors: errors.array() })
  }
  const email = req.body.email
  const password = req.body.password
  bcrypt
    .hash(password, 10)
    .then(hashedPassword => {
      const user = new User({
        email: email,
        password: hashedPassword,
      })
      return user.save()
    })
    .then(() => {
      res.status(201).json({
        message: "User transmission completed!",
      })
    })
    .catch(err => console.log(err))
}

exports.login = (req, res, next) => {
  const email = req.body.email
  const password = req.body.password

  User.findOne({ email: email })
    .then(result => {
      if (!result) {
        const error = new Error("メールアドレスが存在しません")
        error.statusCode = 401
        throw error
      }
      return bcrypt.compare(password, result.password)
    })
    .then(result => {
      if (!result) {
        const error = new Error("パスワードが間違っています")
        error.statusCode = 401
        throw error
      }
      const token = jwt.sign(
        {
          email: email,
        },
        "abcabcabcabcd",
        { expiresIn: "1h" }
      )
      return res.status(200).json({ token: token })
    })
    .catch(err => console.log(err))
}

controllers/book.js

const { validationResult } = require("express-validator")

const Book = require("../model/book")

exports.getBook = (req, res, next) => {
  Book.find().then(books => {
    res.status(200).json({ message: "fetch books successfully", books: books })
  })
}

exports.postBook = (req, res, next) => {
  const errors = validationResult(req)
  if (!errors.isEmpty()) {
    return res
      .status(400)
      .json({ message: "validation errors", errors: errors.array() })
  }
  const title = req.body.title
  const content = req.body.content
  const bookData = new Book({
    title: title,
    content: content,
  })
  bookData
    .save()
    .then(result => {
      console.log(result)
      res.status(201).json({
        message: "Book transmission completed!",
        book: result,
      })
    })
    .catch(err => {
      console.log(err)
    })
}

// const { validationResult } = require("express-validator");

// exports.getBook = (req, res, next) => {
//   res.status(200).json({
//     books: [
//       {
//         id: "aaaaaa",
//         title: "オズの魔法使い",
//         content: "前に進んでいったら、何とかなるという話。",
//       },
//     ],
//   });
// };

// exports.postBook = (req, res, next) => {
//   const errors = validationResult(req);
//   if (!errors.isEmpty()) {
//     return res
//       .status(400)
//       .json({ message: "validation errors", errors: errors.array() });
//   }
//   const id = (Math.random() + 1).toString(36).slice(2, 8);
//   const title = req.body.title;
//   const content = req.body.content;
//   res.status(201).json({
//     message: "Data transmission completed!",
//     post: { id: id, title: title, content: content },
//   });
// };

トークンを検証するためのミドルウェアを作成

トークンの認証が出来た場合は、データを見られる様にします。

また、認証が出来ない場合は、エラーを表示するためのミドルウェアを作成します。

middleware フォルダを作成し、isAuth.js を作成します。

jsonwebtoken を呼び出します。

const jwt = require("jsonwebtoken")

外部で使える様にするため、エクスポートします。

またトークンは、リクエストヘッダーに乗せますので、リクエストヘッダーのAuthorizationを取得します。

module.exports = (req, res, next) => {
  const authHeader = req.get("Authorization")
}

リクエストヘッダーにAuthorizationがない場合、エラーを出力します。

module.exports = (req, res, next) => {
  const authHeader = req.get("Authorization")
  if (!authHeader) {
    const error = new Error("Not Authenticated")
    error.statusCode = 401
    throw error
  }
}

Authorization の中身は、通常『Bearer トークン』です。

『Bearer 』が必要ないので split を使って分割し、トークンの方を指定します。

module.exports = (req, res, next) => {
  const authHeader = req.get("Authorization")
  if (!authHeader) {
    const error = new Error("Not Authenticated")
    error.statusCode = 401
    throw error
  }
  const token = authHeader.split(" ")[1]
}

トークンをデコードして、バックエンドのトークンとあっているか、verify を使って確認します。

module.exports = (req, res, next) => {
  const authHeader = req.get("Authorization")
  if (!authHeader) {
    const error = new Error("Not Authenticated")
    error.statusCode = 401
    throw error
  }
  const token = authHeader.split(" ")[1]
  let decodedToken
  try {
    decodedToken = jwt.verify(token, "abcabcabcabcd")
  } catch (err) {
    err.statusCode = 500
    throw err
  }
}

処理を継続させたいので、next()を書きます。

module.exports = (req, res, next) => {
  const authHeader = req.get("Authorization")
  if (!authHeader) {
    const error = new Error("Not Authenticated")
    error.statusCode = 401
    throw error
  }
  const token = authHeader.split(" ")[1]
  let decodedToken
  try {
    decodedToken = jwt.verify(token, "abcabcabcabcd")
  } catch (err) {
    err.statusCode = 500
    throw err
  }
  next()
}

これで、認証のミドルウェアの作成が一通り完了しました。

ミドルウェアをデータに接続

先程作成したミドルウェアを、book のデータに接続します。

routes フォルダの book.js を開きます。

まずは、isAuthを呼び出します。

const isAuth = require("../middleware/isAuth")

getの第二引数に、isAuthを入れます。

router.get("/get", isAuth, bookController.getBook)

これで完成しましたので、Postman で確認します。

image2

Send ボタンを押してみると、

image3

ステータスコード 401 のエラーが発生しました。

これは、Postman でトークンを設定していなかったから起こったエラーです。

トークンを設定するために、まずは、auth/login に POST して、トークンを取得します。

image4

GET の book/get に戻り、URL 下にある Authorizationw をクリックします。

image5

Type で『Bearer Token』を選択し、先程のトークンを貼り付けます。

image6

改めて、『Send』をクリックすると、

image7

データが取得できました。

トークンが違っていたり、トークンを取得してから、バックエンドで設定した 1 時間が経過すると、以下の様にステータスコード 500 のエラーが発生します。

image8

ブログ一覧