DevGang
Авторизоваться

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)
		...

Все довольно просто и что самое главное, управляемо.

#Python
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу