概要
- ログインと手探りでJWT認証を実装する
JWT認証は手探りなのであってるか不安
ログイン処理実装
通常ログイン+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を作る(プロトタイプ)