Node.js + Express + TypeScriptでWebAPIを作る（4/4）

## 概要

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

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

## ログイン処理実装

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

```ts
// ./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;
```

```sh
> 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に直していきましょう。手直ししたくなる病にかかった感あります。

```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をかませる。

```ts
// ./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が返却される。

```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を作る（プロトタイプ）](https://github.com/yoshida-san/js-web-api)