LoginSignup
45
46

More than 5 years have passed since last update.

Node.js APIで認証付きのMockREST APIサーバの導入

Last updated at Posted at 2017-08-18

はじめに

@ochiochi さんの記事に触発され、Node.jsでWebAPIの認証付きのMockWebAPI(JSON Server)を作成してみました。

JSON Server

JSON Serverは、Node.jsのモジュールで、簡単にREST APIサーバが導入できます。
@ochiochi さんの紹介)

JSON Serverは、Express.jsをベースにしているので、認証機能等を追加する場合には、Express.js用のプログラムを作成します。

JSON Server導入

1. node module

$ npm install json-server -g

2. Mock データベースファイルの作成

REST API によって、操作するデータベースとなるファイルをJSON形式で作成します。

books.json
{
  "books": [
    {
      "id": 1,
      "title": "Math",
      "price": 1000
    },
    {
      "id": 2,
      "title": "Science",
      "price": 1200
    },
    {
      "id": 3,
      "title": "Chemical",
      "price": 1400
    }
  ]
}

3. REST APIサーバ起動

$ json-server --watch ./books.json

デフォルトポート3000で、Webサーバが起動します。

method url request content type
GET http://localhost:3000/books
GET http://localhost:3000/books/1
POST http://localhost:3000/books application/json
PATCH http://localhost:3000/books/1 application/json
PUT http://localhost:3000/books/1 application/json
DELETE http://localhost:3000/books/1

Webサーバサーバを停止する場合には、Ctrl + c

認証機能導入

1. node module

認証トークンの作成と、検証するためのモジュールを導入します。

$ npm install jsonwebtoken

2. Mock ユーザ情報データファイルの作成

ログインに必要なユーザ情報を用意します。このファイルは、認証時に使用する目的以外で公開しません。

users.json
{
  "users": [
    {
      "id": 1,
      "name": "hoge",
      "email": "hoge@email.com",
      "password": "hoge"
    },
    {
      "id": 2,
      "name": "foo",
      "email": "foo@email.com",
      "password": "foo"
    },
    {
      "id": 3,
      "name": "bar",
      "email": "bar@email.com",
      "password": "bar"
    }
  ]
}

2. 認証REST APIプログラムの作成

プログラム内部で、JSON Serverを利用してREST APIサーバを利用します。

auth-api-server.js
//モジュール参照
const fs = require('fs')
const bodyParser = require('body-parser')
const jsonServer = require('json-server')
const jwt = require('jsonwebtoken')

//JSON Serverで、利用するJSONファイルを設定
const server = jsonServer.create()
const router = jsonServer.router('./books.json')

//JSONリクエスト対応
server.use(bodyParser.urlencoded({extended: true}))
server.use(bodyParser.json())

//署名作成ワードと有効期限(1時間)
const SECRET_WORD = 'SECRET1234'
const expiresIn = '1h'

//署名作成関数
const createToken = payload => jwt.sign(payload, SECRET_WORD, {expiresIn})

//署名検証関数(非同期)
const verifyToken = token =>
  new Promise((resolve, reject) =>
    jwt.verify(token, SECRET_WORD, (err, decode) =>
      decode !== undefined ? resolve(decode) : reject(err)
    )
  )

//ユーザDBファイル読み込み
const userdb = JSON.parse(fs.readFileSync('./users.json', 'UTF-8'))

//ログイン関数 true:ok false:ng
const isAuth = ({email, password}) =>
  userdb.users.findIndex(user => user.email === email && user.password === password) !== -1

//ログインRouter
server.post('/auth/login', (req, res) => {
  const {email, password} = req.body

  //ログイン検証
  if (isAuth({email, password}) === false) {
    const status = 401
    const message = 'Incorrect email or password'
    res.status(status).json({status, message})
    return
  }

  //ログイン成功時に認証トークンを発行
  const access_token = createToken({email, password})
  res.status(200).json({access_token})
})

//認証が必要なRouter(ログイン以外全て)
server.use(/^(?!\/auth).*$/, async (req, res, next) => {

  //認証ヘッダー形式検証
  if (req.headers.authorization === undefined || req.headers.authorization.split(' ')[0] !== 'Bearer') {
    const status = 401
    const message = 'Error in authorization format'
    res.status(status).json({status, message})
    return
  }

  //認証トークンの検証
  try {
    await verifyToken(req.headers.authorization.split(' ')[1])
    next()
  } catch (err) {
    //失効している認証トークン
    const status = 401
    const message = 'Error access_token is revoked'
    res.status(status).json({status, message})
  }
})

//認証機能付きのREST APIサーバ起動
server.use(router)
server.listen(3000, () => {
  console.log('Run Auth API Server')
})

3. 認証REST APIプログラムの起動

$ node auth-api-server.js

4. ログインAPI

ログインAPIを使用して、認証トークンを発行します。以降のREST APIアクセスは、認証トークンをヘッダーに付加します。

method url request content type
POST http://localhost:3000/auth/login application/json
  • Request Body
{
  "email": "hoge@email.com",
  "password":"hoge"
}
  • Response Body (200 OK)
{
   "access_token": "XXXXXXXXXXXXXXXX"
}
  • Response Body (401 Unauthorized)
{
  "status": 401,
  "message": "Incorrect email or password"
}

5. 認証付きのAPI

REST APIアクセスは、認証トークンをヘッダーに付加します。

  • Request Header (required access_token)
Authorization: Bearer XXXXXXXXXXXXXXXX

認証トークンが失効していた場合

  • Response Body (401 Unauthorized)
{
  "status": 401,
  "message": "Error access_token is revoked"
}

認証ヘッダー形式エラーの場合

  • Response Body (401 Unauthorized)
{
  "status": 401,
  "message": "Error in authorization format"
}
45
46
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
45
46