Posted at

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を作る(プロトタイプ)