この記事の内容
この記事では、JWT(JSON Web Token)を使用した認証を、Flask-JWTを使用して実装する方法を紹介します。
また、そもそもJWT認証とはどういうものであるのかを解説します。
JWTとは
JSONデータに署名や暗号化を施す方法を定めた規格で、RFC 7519で標準化されています。
JWTを用いることで、認証や認可が行えるようになります。
JWTの構成
JWTは「ヘッダ」、「ペイロード」、「署名」の3つのブロックからなります。
実際のJWTはBase64でエンコードしてそれらを.(ドット)でつないだものです。
署名はどのように作られるのか
改竄などを検知するために、「ヘッダ」と「ペイロード」部分を秘密鍵でハッシュ化した情報を署名とします。
これにより、JWTを発行した人のみが、あっているのかを検証することができます。
ペイロードについて
JWT取得時のシーケンス
クライアントからサーバ側に対して、JWTを取得する場合のシーケンス例を示します。
JWTを使用した、WebAPIのシーケンス
クライアントからサーバ側に対して、JWT認証が必要なWebAPIを呼び出す場合のシーケンスを示します。
Flask-JWT
Flask-JWTを使用した実装方法を紹介します。
Flask-JWTを使用するために、以下のコマンドでFlask-JWTをインストールします。
pip install Flask-JWT
シンプルな実装サンプルに関しては、以下のURLに記載があります。こちらのサンプルを使用して解説していきます。
サンプル
from flask import Flask from flask_jwt import JWT, jwt_required, current_identity from werkzeug.security import safe_str_cmp class User(object): def __init__(self, id, username, password): self.id = id self.username = username self.password = password def __str__(self): return "User(id='%s')" % self.id users = [ User(1, 'user1', 'abcxyz'), User(2, 'user2', 'abcxyz'), ] username_table = {u.username: u for u in users} userid_table = {u.id: u for u in users} def authenticate(username, password): user = username_table.get(username, None) if user and safe_str_cmp(user.password.encode('utf-8'), password.encode('utf-8')): return user def identity(payload): user_id = payload['identity'] return userid_table.get(user_id, None) app = Flask(__name__) app.debug = True app.config['SECRET_KEY'] = 'super-secret' jwt = JWT(app, authenticate, identity) @app.route('/protected') @jwt_required() def protected(): return '%s' % current_identity if __name__ == '__main__': app.run()
サンプルコードの解説
Postmanで呼び出してみる
Postmanを使用して、サンプルで作成したJWT認証を使用してみます。
まずは、/authにPOSTメソッドを使用して、ユーザ名とパスワードを送信します。
すると、JWTを取得できていることがわかります。
取得したJWTを使用して、今度はJWTが必要な/protectedのページにアクセスしてみます。
HeadersのAuthorizationに取得したアクセストークンを以下の様に記載します。
すると、レスポンスが正常に取得できていることがわかります。
署名を1文字変えてみた結果は以下の様に401エラーとなり、署名が不正というエラーがかえってきます。
また、タイムアウト時間も設定することができます。
JWT_EXPIRATION_DELTAクレームを設定することによりタイムアウト時間を設定できます。(デフォルトは500Sec)
例えば30秒にするには以下の様に設定します。
30秒経過後にアクセスすると、401エラーとなり、Signature has expiredとなります。
最後に
今回は、Flask-JWTを使用して、JWT認証を実装してみました。ライブラリを使用することで、簡単に実装することができたと思います。JWTに関しては、設定によっては脆弱性が生まれる可能性があるので、その点に関しては押さえておく必要があります。例えば、algクレームに署名無し (none) を使用することで不正なトークンを処理してしまうといったことがありますので、適切な情報収集をして使用することをおすすめいたします。
コメント