Вкратце:
Flask — micro web framework. По сути, тонкая обёртка вокруг wsgi-сервера werkzeug.
Flask-Security — расширение (extension) для flask, которое реализует возможность аутентификации и авторизации («входа на сайт», другими словами — логина), регистрации пользователей. Flask-Security сам по себе использует другие сторонние расширения для реализации нужного функционала (например: flask-login для логина, flask-wtf для обработки форм).
Задача: во время инициализации БД создать пользователя с паролем. Примерно как это делает Django при первом syncdb с подключенным приложением django.contrib.auth.
Проблемы и решение:
Хранить пароли в открытом виде не модно да и не безопасно. Пароль требуется защитить понятным для flask-security методом.
Процедура сокрытия пароля не прозрачна на уровне ORM (в данном случае sqlalchemy).
Для инициализации БД воспользуемся расширением flask-script, которое позволяет просто реализовать CLI (command line interface — интерфейс командной строки) для некоторых действий в нашем приложении.
Версия 1: Только хардкор, только хардкод!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | from flask.ext import script import app # module with our application from extensions import db # sqlalchemy.SQLAlchemy instance import models # our custom models manager = script.Manager(app.app) @manager.command def initdb(): """Reset and init database.""" db.drop_all() db.create_all() user = models.User( username=u'admin', email=u'admin@example.com', password=u'password', ) db.session.add(user) db.session.commit() |
Запуск: python manage.py initdb
Минусы: пароль захардкожен. Flask-Security будет работать только если в настроках установлен plaintext в качестве формата паролей.
Версия 2: Убираем хардкод
Меняем:
1 | password=u'password', |
На:
1 | password=raw_input('Enter initial user password: '), |
Да, всё так элементарно, но сразу почему-то в голову не пришло.
Версия 3: солим и хэшируем
Добавляем импорт:
1 | from flask.ext.security import utils |
Меняем:
1 | password=raw_input('Enter initial user password: '), |
На:
1 2 3 | password=utils.encrypt_password( raw_input('Enter initial user password: ')), |
Версия 4: DRY, less harcode
Убираем остальной хардкод, используем DRY (don’t repeat yourself). В итоге всё выглядит так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | @manager.command def initdb(): """Reset and init database.""" db.drop_all() db.create_all() user_defaults = { 'username': 'admin', 'email': 'admin@example.com', 'password': 'admin', } input_msg = 'Enter %s [%s]: ' for key, value in user_defaults.iteritems(): user_defaults[key] = raw_input(input_msg % (key, value)) or value user_defaults['password'] = utils.encrypt_password( user_defaults['password']) user = models.User(**user_defaults) db.session.add(user) db.session.commit() |
Выглядит вполне симпатично. Мои познания flask ограничены 3 вечерами, но, надеюсь, в данном примере нет каких-то очевидных нелепостей.