Photo by Tyler Franta / Unsplash

Background

想設計Json based的api server, 但是Flask-JWT好像沒在維護了. 所以紀錄一下如何用PyJWT來實作.

Installation

$ pip3 install pyjwt

Basic

基本JWT的Flow如下圖, 基本上網路上很多相關理論的介紹. 這邊只講實作面的東西.

flow-cookie-session-large

from passlib.apps import custom_app_context as pwd_context
from sqlalchemy import Column, Integer, String, DateTime
from pprint import pprint
import jwt
import datetime

class User(db.Model):

    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    email = Column(String)
    password = Column(String)
    status = Column(Integer)
    create_time = Column(DateTime)
    last_login = Column(DateTime)

    def __init__(self, email, password):
        self.email = email
        self.password = self.hash_password(password)
        self.create_time = datetime.datetime.now()
        self.status = 0

    def hash_password(self, password):
        return pwd_context.encrypt(password + app.config['SECRET_KEY'])

    def verify_password(self, password):
        return pwd_context.verify(
            password + app.config['SECRET_KEY'], self.password)
            
    def encode_auth_token(self):
        """
        Generates the Auth Token
        :return: string
        """
        try:
            payload = {
                'exp': datetime.datetime.now() + datetime.timedelta(hours=6, seconds=0),
                'iat': datetime.datetime.now(),
                'sub': self.email
            }

            return jwt.encode(
                payload,
                app.config['SECRET_KEY'],
                algorithm='HS256'
            )

        except Exception as e:
            return e

    @staticmethod
    def decode_auth_token(auth_token):
        """
        Decodes the auth token
        :param auth_token:
        :return: integer|string
        """
        try:
            payload = jwt.decode(auth_token, app.config['SECRET_KEY'])
            user = User.query.filter_by(email=payload['sub']).first()
            return user
        except jwt.ExpiredSignatureError:
            return 'Signature expired. Please log in again.'
        except jwt.InvalidTokenError:
            return 'Invalid token. Please log in again.'

基本上值得注意的就 encode_auth_token & decode_auth_token 這兩個 function.

Reference