Node.js
MongoDB
Express
TypeScript

Node.js + Express + TypeScriptでWebAPIを作る(4/4)

概要

  • ログインと手探りでJWT認証を実装する

JWT認証は手探りなのであってるか不安:thinking:

ログイン処理実装

通常ログイン+JWT認証を利用しようと思います。今回はパスワードのハッシュ化は省略しますが、パスワードを生で持つことは止めましょう。具体的に言うとオランウータンに核爆弾のスイッチを掃除させるぐらいに危険です。
ってことでまずはuidとpasswordをPostしてPostされたPasswordとDBにあるパスワードが一致しているか見て、一致していたらTokenを返すところまで実装します。要するに通常のログインです。

// ./src/rotes/auth/index.ts
import Express from "express";
import jwt from "jsonwebtoken";
import mongodbClient from "../../dbClient";
import IDocumentUser from "../../documents/IdocumentUser";
import noImpl from "../../noImpl";

const router = Express.Router();

router.delete("/signout", noImpl);

router.post("/signin", (req, res, next) => {
    const uid: string = req.body.uid;
    console.log(req.body);
    mongodbClient((ce, client, db) => {
        if (ce) {
            client.close();
            res.status(500);
            res.json({
                message: ce.message,
                requestPath: req.path,
            });
            return next(ce);
        }

        const collection = db.collection<IDocumentUser>("users");
        collection.findOne({ uid }, (e, result) => {
            if (e) {
                client.close();
                res.status(500);
                res.json({
                    message: e.message,
                    requestPath: req.path,
                });
                return next(e);
            }

            client.close();

            if (result === null || result.password !== req.body.password) {
                res.json({ signin: false, message: "nothing uid or missing password" });
                return;
            } else {
                const payload = {
                    name: result.uid,
                };
                const token: string = jwt.sign(payload, "secretKey");
                res.json({
                    success: true,
                    token,
                });
            }
        });
    });
});

export default router;
> curl -X POST -H "Content-Type: application/json" -d '{"uid":"1", "password":"piyo"}' localhost:3000/auth/signin
{"success":true,"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiMSIsImlhdCI6MTU0NTcwNDQxM30.IS-4u24T1KZrZTXFynWRsMwDxs9WiH7GAan0CEakhHo"}

こんな感じでしょうか。

JWT認証実装

続いてJWT認証を実装していきます。と、その前にdbClient.ts, noImpl.ts, log.tsもcommonディレクトリに移動しておきましょう。とりあえずぶっ込んでおきます。IDocumentUser.tsは名前が長いのでIUser.tsに直していきましょう。手直ししたくなる病にかかった感あります。

// ./src/common/verifyToken.ts
import { NextFunction, Request, Response } from "express";
import jwt, { VerifyOptions } from "jsonwebtoken";

export default (req: Request, res: Response, next: NextFunction) => {
    const token = req.body.token || req.query.token || req.headers["x-access-token"];

    if (token) {
        jwt.verify(token, "secretKey", (error: any, decoded: any) => {
            if (error) {
                res.status(403);
                return res.json({ success: false, message: "Authentication of token failed." });
            } else {
                console.log(decoded);
                next();
            }
        });
    } else {
        res.status(403);
        res.json({
            message: "Token nothing.",
            success: false,
        });
    }
};

とりあえずこんな感じで実装。簡単に書いてるけど結構時間使った(´・ω・`)と言うかdecodedの受け渡しが上手くいかない...Requestを拡張したInterface作れば解決しそう。

server.tsのルーティングにVerifyTokenをかませる。

// ./src/server.ts
import verifyToken from "./common/verifyToken";

app.use("/users", verifyToken, users);
app.use("/test", verifyToken, test);

authには通さないでOK。authって名前も何か違う感半端ねぇ。
さすがにcurlでx-access-token付けて投げるの面倒なのでPostmanから投げる。まずは/auth/signin{"uid":"1", "password":"piyo"}をPostしてTokenを取得。/test/dbConnectにPostする時にheaderにx-access-tokenを含める。値は/auth/signinで返ってきたtokenを設定。{ "msg": ":-)" }が返ってくればJWT認証成功。tokenをてきとーに改変してPostすると以下のようなjsonが返却される。

{
    "success": false,
    "message": "Authentication of token failed."
}

環境作って簡単にルーティング設定して、DB接続して、DB読み(書きもできたようなもん)、JWT認証までざーっと通しました。おそらくこの内容+αでJavascript(Node.js + Express + TypeScript)を使って「動くWeb API」は実装できるかと思います。

出来上がったやつ

必要無いかもしれませんが、置いときます。
yoshida-san/js-web-api: Node.js + Express + TypescriptでWeb APIを作る(プロトタイプ)