utamaro’s blog

誰かの役に立つ情報を発信するブログ

pythonでjwtを使う際に作ったutilについて

作成したjwtのutilを紹介します。

作成したutilですが、まだまだ修正途中のものです。使用する場合は注意してください。

jwtについての詳細についてはこちらを参照してください。

https://jwt.io/introduction/

コードと解説の距離が離れると読みづらいと思いますので、できる限りコメントを書きました。

そちらを見てください。

import datetime
from datetime import datetime, timedelta

import jwt
import pytz


class JwtContent(object):

    JWT_EXPIRE_DAY = 1

    JWT_ALGORITHM = "HS256"

    JWT_SECRET_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

    JWT_COOKIE_NAME = "Authentication"

    COOKIE_EXPIRE_FORMAT = "%a, %d-%b-%Y %H:%M:%S GMT"


class JwtUtil(object):

    @staticmethod
    def create_token(payload, is_revoke=False):
        """
        payloadを使用してjwtトークンを発行する
        :param is_revoke: Trueにするとtokenを有効期限切れにする
        :param payload: dict object
        :return: jwtでエンコードされたトークン
        """
        timezone = pytz.timezone('Asia/Tokyo')
        now = datetime.now(tz=timezone)
        if is_revoke:
            delta = timedelta(days=-JwtContent.JWT_EXPIRE_DAY)
        else:
            delta = timedelta(days=+JwtContent.JWT_EXPIRE_DAY)
        result = now + delta
        payload["exp"] = result
        encode_data = jwt.encode(
            payload,
            JwtContent.JWT_SECRET_KEY,
            algorithm=JwtContent.JWT_ALGORITHM
        )
        return encode_data.decode('utf-8')

    @staticmethod
    def is_expired_token(jwt_token):
        if jwt_token is None:
            return True, None, None
        try:
            decode_data = jwt.decode(
                jwt_token,
                JwtContent.JWT_SECRET_KEY,
                algorithms=[JwtContent.JWT_ALGORITHM]
            )
            return False, decode_data, None
        except jwt.ExpiredSignatureError as e:
            # 有効期限切れ
            return True, None, e
        except jwt.InvalidTokenError as e:
            # decodeが実行できなかった
            return True, None, e
        except Exception as e:
            return True, None, e

    @staticmethod
    def is_expired_session_token(request, cookie_name):
        """
        requestからトークンのクッキーを取り出してそのクッキーの有効期限を判定する
        :param cookie_name:
        :param request:
        :return: 成功時デコードされたデータ(dict object). 失敗時True
        """
        jwt_token = request.COOKIES.get(cookie_name)
        return JwtUtil.is_expired_token(jwt_token)

    @staticmethod
    def set_jwt_cookie(response, jwt_cookie_data, cookie_name):
        """
        responseオブジェクトにjwtトークンキーをセットする
        jwtのexpireはcommon.config.JWT_EXPIRE_DAYによって変わる
        また、タイムフォーマットはAsia/Tokyoのゾーンとしている
        セキュリティのため、httponlyをtrueにしている
        :param response:
        :param jwt_cookie_data:
        :return:
        """
        timezone = pytz.timezone('Asia/Tokyo')
        expire_datetime = datetime.now(tz=timezone) + timedelta(days=+JwtContent.JWT_EXPIRE_DAY)
        expire_datetime_str = expire_datetime.strftime(
            JwtContent.COOKIE_EXPIRE_FORMAT
        )
        response.set_cookie(
            cookie_name,
            jwt_cookie_data,
            expires=expire_datetime_str, httponly=True
        )
        return response

    @staticmethod
    def delete_jwt_cookie(response, cookie_name):
        response.delete_cookie(cookie_name)
        return response