Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9034

node + expressでJWT (2021年1月)

$
0
0

随分昔に同じ趣旨の記事を書いたのですが、再度書き直してみます(あまり変わってない)。

準備

作業場作成

ひとまず作業場所を確保し、必要なモジュールをインストール。body-parserはもういらない。

mkdir jwt-test
cd jwt-test
npm init -y
npm install express jsonwebtoken

実装前に検証

実装に入る前にJWTの生成と検証のコア部分をワンライナーで検証。

生成

なにやらややこしそうに思うが、[ヘッダ].[ペイロード].[署名]をそれぞれbase64でエンコードしているだけ。
署名部はsecret(ここではmy_secretという文字列)を利用してHS256で署名している。

node -e"console.log(require('jsonwebtoken').sign({username:'hoge'},'my_secret'))"

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImhvZ2UiLCJpYXQiOjE2MTE3OTA3Nzl9.MbcALpRUEu9KxGZ5S1qLoieb41_dr-i2o__QVnlVTow

サイン時に、 sign({username:'hoge'},'my_secret',, { expiresIn: '1h' })とすることで有効期限を設定可能。

検証

node -e"console.log(require('jsonwebtoken').verify('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImhvZ2UiLCJpYXQiOjE2MTE3OTA3Nzl9.MbcALpRUEu9KxGZ5S1qLoieb41_dr-i2o__QVnlVTow','my_secret'))"{ username: 'hoge', iat: 1611790779 }

メモ

大規模?な利用シーンでは署名と検証に公開鍵技術を利用する場合もあると思うが、jsonwebtokenは対応しているよう。詳しくは本家サイトを見る。

実装

では、簡単なJWTを利用したAPI認証機能を実装する。主な機能は以下の感じ。

  • /loginにusername, passwordをPOSTで送信し、認証OKならtoken(JWT)を発行。
  • /protectedへのアクセスにはAuthorizationヘッダにBearer+tokenを付与し認証OKならコンテンツを戻す。
  • 認証機構はverifyToken()という外部関数とし実装し、app.get('/protecte')のミドルウエアとして適用する。

では実装します。

index.js
varexpress=require('express');varapp=express();varjwt=require('jsonwebtoken');app.use(express.json());app.use(express.urlencoded({extended:true}));app.listen(3000,function(){console.log("App start on port 3000");})//認証無しAPIapp.get('/',function(req,res){res.json({status:"OK"});})//認証+Tokenの発行app.post('/login',function(req,res){//ID,PW取得varusername=req.body.username;varpassword=req.body.password;//認証//実際はDB等と連携if(username==="hoge"&&password==="password"){//token生成(フォマットは適当だが、有効期限を設定)consttoken=jwt.sign({username:username},'my_secret',{expiresIn:'1h'});res.json({token:token});}else{res.json({error:"auth error"});}})//認証有りAPIapp.get('/protected',verifyToken,function(req,res){res.send("Protected Contents");})functionverifyToken(req,res,next){constauthHeader=req.headers["authorization"];//HeaderにAuthorizationが定義されているかif(authHeader!==undefined){//Bearerが正しく定義されているかif(authHeader.split("")[0]==="Bearer"){try{consttoken=jwt.verify(authHeader.split("")[1],'my_secret');//tokenの内容に問題はないか?//ここでは、usernameのマッチと有効期限をチェックしているが必要に応じて発行元、その他の確認を追加//有効期限はverify()がやってくれるみたいだがいちおう・・・if(token.username==="hoge"&&Date.now()<token.exp*1000){console.log(token);//問題がないので次へnext();}else{res.json({error:"auth error"})}}catch(e){//tokenエラーconsole.log(e.message);res.json({error:e.message})}}else{res.json({error:"header format error"});}}else{res.json({error:"header error"});}}

実装できたら実行。

node index.js

動作確認

curlを利用して動作確認をしてみます。

tokenの取得

まずは認証してtokenを取得します。

curl -s-X POST -H'Content-Type: application/json'-d'{"username":"hoge","password":"password"}' http://localhost:3000/login

{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImhvZ2UiLCJpYXQiOjE2MTE3OTEyMDksImV4cCI6MTYxMTc5NDgwOX0.Gy_3r3T-AQG8iL28LE1xzVNMEJDKTtgTyMRiaSNpQiM"}

curl -X POST -d "username=hoge&password=password" http://localhost:3000/loginでも可。

tokenの利用

取得したtokenを利用して/protectedにアクセスしてみます。

curl -X GET http://localhost:3000/protected -H"Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImhvZ2UiLCJpYXQiOjE2MTE3OTEyMDksImV4cCI6MTYxMTc5NDgwOX0.Gy_3r3T-AQG8iL28LE1xzVNMEJDKTtgTyMRiaSNpQiM"

Protected Contents

うまく表示されました。

その他

リフレッシュはどうする?

調べ中。とりあえず下記を見る。まあ、実運用ではexpiredであれば再ログインさせ、そのときに再取得しればいいとは思う。
https://solidgeargroup.com/refresh-token-autenticacion-jwt-implementacion-nodejs/


Viewing all articles
Browse latest Browse all 9034

Trending Articles