FullStackOpen Part4-d Token Authentication メモ
トークン認証は以下のような仕組み
トークン機能を実装するためにjsonwebtokenを使用する
npm install jsonwebtoken
login用のエンドポイントを用意する。
./controller/login.js
const jwt = require('jsonwebtoken')
const bcrypt = require('bcrypt')
const loginRouter = require('express').Router()
const User = require('../models/user')
loginRouter.post('/', async (request, response) => {
const { username, password } = request.body
const user = await User.findOne({ username })
const passwordCorrect = user === null
? false
: await bcrypt.compare(password, user.passwordHash)
if (!(user && passwordCorrect)) {
return response.status(401).json({
error: 'Invalid username or password'
})
}
const userForToken = {
username: user.username,
id: user._id,
}
const token = jwt.sign(userForToken, process.env.SECRET)
response
.status(200)
.send({ token, username: user.username, name: user.name })
})
module.exports = loginRouter
.envファイルにSECRET環境変数を設定する
ルーターをapp.jsに入れると機能する
Limiting creating new notes to logged-in users
ノート作成をログイン済みユーザーのみにする場合はAuthorizationヘッダを使用する
今回はベアラー認証を使用し、Authorizationヘッダは以下のような形に
Bearer eyJhbGciOiJIUzI1NiIsInR5c2VybmFtZSI6Im1sdXVra2FpIiwiaW
notes.jsを以下のように変更し、トークンによってポストできるかどうか決める
getTokenFromヘルパー関数を設定しておく
const getTokenFrom = request => {
const authorization = request.get('authorization')
if (authorization && authorization.startsWith('Bearer ')) {
return authorization.replace('Bearer ', '')
}
return null
}
notesRouter.post('/', async (request, response, next) => {
const body = request.body
const decodedToken = jwt.verify(getTokenFrom(request), process.env.SECRET)
if (!decodedToken.id) {
return response.status(401).json({ error: 'Invalid token!' })
}
const user = await User.findById(decodedToken.id)
const note = new Note({
content: body.content,
important: body.important || false,
user: user.id
})
const savedNote = await note.save()
user.notes = user.notes.concat(savedNote._id)
await user.save()
response.status(201).json(savedNote)
})
エラーハンドラー(./utils/middleware.jsで無効なトークンだった時の処理'JsonWebTokenError'を施す
const errorHandler = (error, request, response, next) => {
logger.error(error.message)
if (error.name === 'CastError') {
return response.status(400).send({ error: 'malformatted id' })
} else if (error.name === 'ValidationError') {
return response.status(400).json({ error: error.message })
} else if (error.name === 'JsonWebTokenError') { return response.status(400).json({ error: error.message }) }
next(error)
}
Postmanからリクエストする際はヘッダにAuthorizationを指定する
Problems of Token-based authentication
現在の設定だとトークンが無期限で使えてしまい危ない
トークンの有効期限をlogin.jsで設定する
...
const userForToken = {
username: user.username,
id: user._id,
}
//Token expires in 60*60 seconds
const token = jwt.sign(userForToken, process.env.SECRET, {
expiresIn: 60 * 60
})
response
.status(200)
.send({ token, username: user.username, name: user.name })
...
middleware.jsにトークン失効エラーを記述
const errorHandler = (error, request, response, next) => {
logger.error(error.message)
if (error.name === 'CastError') {
return response.status(400).send({ error: 'Malformatted id' })
} else if (error.name === 'ValidationError') {
return response.status(400).json({ error: error.message })
} else if (error.name === 'JsonWebTokenError') {
return response.status(400).json({ error: error.message })
} else if (error.name === 'TokenExpiredError') {
return response.status(401).json({
error: 'token expired'
})
}
next(error)
}
この記事が気に入ったらサポートをしてみませんか?