Python декораторы и кастомная авторизация на Flask
 
                            
                            
                            Для начала про декораторы и зачем они мне вообще понадобились
Как-то давно искал просто и наглядный пример как организовать авторизацию у себя на проекте. Подавляющее большинство примеров били или сложными, или плодили большое количество магии на проекте. Мне же хотелось управлять процессом авторизации.
Среди всего того бардака нашелся пример с декоратором, в статье предлагали проверять наличие куки в запросе и если она присутствовала искать ее уже в соответствующей модели.
Декоратор - это возможность расширения функционала имеющейся функции(объекта), подробней тут wiki
Простой пример
Для начала про сам декоратор, простой пример:
def strong(handler): def wrap(): return '<strong>' + handler() + '</stron>' return wrap
И выведем избитое Hello world
@strong def hello(): return 'Hello world' print(hello()) # <strong>Hello world</strong>
По сути, декоратор - это функция обертка над другой функцией.
Авторизация на Flask
Простой и самый топорный вариант
from app.models.UserModel import UserModel
from flask import abort
from flask import request
def authenticate(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        token = request.cookies.get('sid')
        if UserModel.query.filter_by(token=token).first():
            return func(*args, **kwargs)
        abort(401)
    return wrapper
Проверяем, если есть кука sid и существует запись с таким же пользователем, отдаем страницу по заданому роуту, если нет, делаем abort(401)
@authenticate
@app.route('/create-article')
def create_article_handler():
	...
Это простейший вариант работы с авторизацией, поверх него можно накрутить много разного. Я например используя flask_restful сделал промежуточный метод синглтон для получения авторизованного пользователя как на примере ниже:
from flask_restful import Resource
class Base(Resource)
	_user = False
	authenticated = False
	@property
    def current_user(self):
        if self._user is False:
            token = request.cookies.get('sid')
            uid = app_redis.get(token)
            if uid:
                self._user = UserModel.query.filter_by(
                    id=self.to_int(uid)
                ).first()
        return self._user
Модифицируем наш декоратор:
def authenticate(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        _self = args[0] if len(args) else None
        user = False
        if not getattr(func, 'authenticated', True):
            return func(*args, **kwargs)
        if hasattr(_self, 'current_user'):
            user = _self.current_user
        if user:
            return func(*args, **kwargs)
        abort(401)
    return wrapper
И собственно пример использования:
class ArticleController(Base) @authenticate def put(self) ...
Все довольно просто и что самое главное, управляемо.