はじめに
React+ReduxアプリケーションにNode.js(express)でAPIを作り、jsonwebtoken(JWT)で認証・認可周りの処理を実装してみました。今回はAPI側の実装の内容を書いていきます。
ソースコードはGitHubにありますので、参考にしてください。
使ったもの
- Node(v12.15.0)
- express(v4.17.1)
- jsonwebtoken(v8.5.1)
- body-parser(v1.19.1)
- nodemon(v2.0.3)
- REST Client(VSCodeの拡張機能)
ディレクトリ構成
root/
├ api/
│ ├ login.js
│ └ users.js
├ config/
│ └ jwt.config.js
├ middlewares/
│ └ verifyToken.js
├ app.js
└ request.rest
作るもの
[POST] /api/v1/login
ユーザーIDとパスワードを付与してリクエストすれば、認証が通ればjwtでトークンを返す
[GET] /api/v1/users
トークンをヘッダーに付与してリクエストすれば、ユーザー情報を返す
プロジェクト作成
プロジェクト作成して、必要なパッケージをインストールします。
npm init -y
npm install --save express jsonwebtoken body-parser nodemon
app.jsを作成
とりあえずexpressを読み込んで、appで初期化して、app.listenで起動する普通の流れです。
ルーティングは別ファイルにするので、express.Routerを初期化してリターンします。
constexpress=require("express");constbodyParser=require("body-parser");constapp=express();app.use(bodyParser.urlencoded({extended:true}));app.use(bodyParser.json());app.use("/api/v1",(()=>{constrouter=express.Router();router.use("/login",require("./api/login.js"));router.use("/users",require("./api/users.js"));returnrouter;})());app.listen(5000,function(){console.log("Example app listening on port 5000!");});
login.jsを作成
認証は本来はデータベースから行うが今回は割愛します。
constrouter=require("express").Router();constjwt=require("jsonwebtoken");constconfig=require("../config/jwt.config");// POST /api/v1/loginrouter.post("/",(req,res)=>{// 本来はデータベースからユーザーIDとパスワードを認証するが割愛if(req.body.userId=="00001"&&req.body.passWord=="qwerty"){constpayload={userId:req.body.userId,};consttoken=jwt.sign(payload,config.jwt.secret,config.jwt.options);res.json({isSuccess:true,token:token,});}else{res.json({isSuccess:false,message:"ユーザーIDまたはパスワードが違います。",});}});module.exports=router;
jwt.config.jsに設定を記載する。
module.exports={jwt:{secret:"cdfa54a89e0fbd4596213bf175336cfe05a78a73383f6dab39b8d374e7dceba53630546ff4c998b7bab9e53eaab2519a48e970b094315cf7472b811e45c1ea29",options:{algorithm:"HS256",expiresIn:"20m",},},};
シークレットキーはコマンドプロンプトで以下入力で取得したものです。
node
require("crypto").randomBytes(64).toString("hex")
ログインリクエストを試してみる
nodemonをインストールしてあれば以下で起動できます。
nodemonapp.js
今回リクエストにはVSCodeの拡張機能の[REST Client]を使います。request.restファイルに以下のように記述すれば、
上部に[Send Request]が表示されるのでクリックすれば、リクエストできます。
POSThttp://localhost:5000/api/v1/loginContent-Type:application/json{"userId":"00001","passWord":"qwerty"}
認証に成功すれば以下レスポンスがあると思います。これでトークンが取得できましたで、ユーザー情報を取得します。
{"isSuccess":true,"token":"xxxxxxxxxxxxxxxxxxxx"}
verifyToken.jsを作成
まずトークンを認証するミドルウェアを作成します。
リクエストヘッダーには以下のようにトークンを付与します。
Authorization: Bearer xxxxxxxxxxxxxxxxxxxx
ヘッダーからトークンを取得して認証処理を行います。
認証が成功したら、req.decodedにpayloadで設定した値が格納される。
constjwt=require("jsonwebtoken");constconfig=require("../config/jwt.config");functionverifyToken(req,res,next){// splitで半角スペースで分割して後ろ側がTokenになるconstauthHeader=req.headers.authorization;consttoken=authHeader&&authHeader.split("")[1];if(token){jwt.verify(token,config.jwt.secret,function(error,decoded){if(error){returnres.status(403).send({isSuccess:false,message:"トークンの認証に失敗しました。",});}else{req.decoded=decoded;next();}});}else{returnres.status(401).send({isSuccess:false,message:"トークンがありません。",});}}module.exports=verifyToken;
users.jsを作成
こちらもは本来はデータベースから情報を取得するが今回は割愛します。
先ほど作成した[verifyToken]を付与すれば、認証が行われ[req.decoded]にユーザーIDが格納されるので、その値をもとにユーザー情報を取得してレスポンスを返します。
constrouter=require("express").Router();constverifyToken=require("../middlewares/verifyToken");// GET /api/v1/usersrouter.get("/",verifyToken,(req,res)=>{// 本来はデータベースからユーザーIDを元にデータを取得するが割愛letresults={};if(req.decoded.userId=="00001"){results={userId:req.decoded.userId,name:"Tom",};}res.json(results);});module.exports=router;
ユーザー情報取得リクエストを試してみる
先ほどログインした時のトークンをリクエストヘッダーに付与して、リクエストする。
GEThttp://localhost:5000/api/v1/usersAuthorization:Bearerxxxxxxxxxxxxxxxxxxxx
認証に成功すれば以下のようにレスポンスがあるはずです。
{"userId":"00001","name":"Tom"}
まとめ
これで、API側の実装は完了です。本来はデータベースが必須になるのでそのうちMySqlかMongoDBあたりで実装するかもしれません。
とりあえず次回はフロント側の実装をしていきたいと思います。何かまずいところあればコメントお願いします。
参考にしたもの
Introduction to JSON Web Tokens
JWT Authentication Tutorial - Node.js