Flask настройка reCAPTCHA от Google

Вездесущий спам — читал где то, что одно время 80% почтового трафика это был SPAM.

Сейчас уже почтового спама не так много доходит до нас (просто средства борьбы с ним стали лучше).

Я столкнулся со спамом в формах обратной связи на сайтах, да и вообще в формах которые на сайтах позволяют писать и отправлять сообщения. 

С годами, образовалось большое количество сайтов, и клиенты стали жаловаться на спам, конечно при разработке были сделаны простые защиты (скрытое поле и/или 2+2 и т. д. и т. п.) так же был опыт использования reCAPTCHA v2 — но были свои нюансы.

reCAPTCHA v2 считаю, что это хорошее решение. Да и ещё оно работает из коробки с flask-wtf примерно с 2017 года. Раньше нужно было «колхозить».

Решил написать для себя простой шаблон, ничего лишнего, форма обратной связи в контактах сайта защищенная reCAPTCHA. Мне легче использовать такую выжимку из проекта, чем копаться в большом готовом проекте с кучей библиотек. Здесь нечего лишнего, бери и используй.

Что понадобиться?

  1. Ключи от google публичный и приватный. (Я создал для хоста 127.0.0.1 возможно для теста подойдут они. А так нужно при создании указывать домен на котором будет сайт с капчей.)
  2. Flask и flask-wtf.

Структура проекта

.
├── app.py
├── forms.py
├── requirements.txt
└── templates
    ├── base.html
    └── index.html

Пошаговые действия

Создать виртуальное окружение для python, всё как обычно:

python3.7 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

Содержимое requirements.txt

Flask==1.1.2
Flask-WTF==0.14.3

Создаю директорию для шаблонов:

mkdir templates

Создаю файл base.html (в директории templates) следующего вида, строки 8,9 содержат блок который будет расширен содержимым файла index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Flask RecaptchaField simple - {{ title }}</title>
</head>
<body>
{% block content %}
{% endblock content %}
</body>
</html>

Содержимое файла index.html (в директории templates). Строка 1 указывает какой шаблон будет расширен текущим. Строка 5 будет содержать сообщение об успехе или провале валидации. Собственно в 11 строке содержится recaptcha.

{% extends "base.html" %}
{% block content %}

    {% if msg %}
	Результат: {{ msg }}	
    {% endif %}
    
    <form action="/" method="post">
        {{ form.csrf_token }}	
        {{ form.text.label }} {{ form.text(size=20) }}
        {{ form.recaptcha }}
        <input type="submit" value="Отправить">
    </form>

{% endblock %}

Следующий файл forms.py (корень проекта). Строка 8 содержит поле комментарий DataRequired обозначает обязательно для заполнения. Строка 9 recaptcha поле с «галочкой».

from flask_wtf import FlaskForm
from flask_wtf import RecaptchaField
from wtforms import TextField
from wtforms.validators import DataRequired


class ContactForm(FlaskForm):
    text = TextField('Комментарий', validators=[DataRequired()])
    recaptcha = RecaptchaField()

И наконец самый главный файл приложения app.py (корень проекта).

Строка 5 — ранее описанная форма.

Строка 10, 11 — ключи которые нужно получить в google используя аккаунт google.

Строка 16 — форма для передачи в шаблон и проверки валидности.

Строка 18 — если метод POST значит была нажата в форме кнопка submit и соответственно нужно проверить полученные данные на валидность.

Строка 19 — проверка данных на валидность.

Если валидация пройдена, то msg примет значение «Успех!» иначе «Ошибка валидации».

from flask import Flask
from flask import request
from flask import render_template
#  форма с валидацией и капчей
from forms import ContactForm
app = Flask(__name__)
app.config['SECRET_KEY'] = "12345"

#  ключи recaptcha от google
app.config['RECAPTCHA_PUBLIC_KEY'] = "6Ld74-oUAAAAAJC0UOY6PtrOrNcxQ2VQCfGAqBOC"
app.config['RECAPTCHA_PRIVATE_KEY'] = "6Ld74-oUAAAAAD2_Jl2IVKh2uCCI9OPX_7oTdLz4"


@app.route('/', methods=['GET', 'POST'])
def index():
    form = ContactForm()
    msg = ""
    if request.method == "POST":
        if form.validate_on_submit():
            msg="Успех!"
            #  отправить почту, записать в БД
        else:
            msg="Ошибка валидации"
            #  обработать ошибку

    return render_template("index.html",
                           title="index page",
                           form=form,
                           msg=msg)


if __name__ == '__main__':
    app.run(debug=True)

Запуск проекта:

python3 app.py
Заполнили комментарий и нажали на галочку
Успешная валидация
Ошибка валидации
Пример работы reCAPTCHA с Flask

В видео видно, что если ошибиться несколько раз, будет показана капча и просто «галочкой» уже не отделаться.

В заключении

Я расписал подробно шаги для того, что бы запомнить самому, делать всё на автомате. В будущем буду экономить время и не лениться добавлять валлидацию там где нужно. Это не переводная статья и не куски документации один к одному — это то что я использую в своих проектах.

В новой версии flask-wtf появиться параметр RECAPTCHA_DISABLE  который позволит красиво отключать и включать проверку капчи.

А как быть, если нужно отключить проверку  капчи сейчас?

Вообще это одна из проблем, почему мне не нравилось использовал данную капчу, решение пока у меня такое, создавать две одинаковые формы с reCAPTCHA и без. Пример кода ниже forms.py и app.py.  Выделил строки которые поменялись.

Файл forms.py

from flask_wtf import FlaskForm
from flask_wtf import RecaptchaField
from wtforms import TextField
from wtforms.validators import DataRequired

class ContactForm(FlaskForm):
    text = TextField('Комментарий', validators=[DataRequired()])

class ContactRecaptchaForm(ContactForm):
    recaptcha = RecaptchaField()

Файл app.py

from flask import Flask
from flask import request
from flask import render_template
app = Flask(__name__)
app.config['SECRET_KEY'] = "12345"

#  ключи recaptcha от google
app.config['RECAPTCHA_PUBLIC_KEY'] = "6Ld74-oUAAAAAJC0UOY6PtrOrNcxQ2VQCfGAqBOC"
app.config['RECAPTCHA_PRIVATE_KEY'] = "6Ld74-oUAAAAAD2_Jl2IVKh2uCCI9OPX_7oTdLz4"
app.config['RECAPTCHA_DISABLE'] = True #  будет капча или нет

#  форма с валидацией и капчей или без неё.
#  в новой версии flask-wtf планируется сделать RECAPTCHA_DISABLE красиво
#  из коробки, это временное решение
if app.config['RECAPTCHA_DISABLE'] == True:
    from forms import ContactRecaptchaForm as ContactForm
else:
    from forms import ContactForm


@app.route('/', methods=['GET', 'POST'])
def index():
    form = ContactForm()
    msg = ""
    if request.method == "POST":
        if form.validate_on_submit():
            msg="Успех!"
            #  отправить почту, записать в БД
        else:
            msg="Ошибка валидации"
            #  обработать ошибку

    return render_template("index.html",
                           title="index page",
                           form=form,
                           msg=msg)


if __name__ == '__main__':
    app.run(debug=True)

Готовый код с примером Flask + reCAPTCHA v2 Google

Можно скачать его тут.

git clone https://github.com/newivan/flask-simple-captcha

SQLite3 создать dump базы данных и восстановить из него

Бывает необходимость, поработать с текстом в базе SQLite. Для этого я выгружаю в sql все таблицы с данными, провожу манипуляцию и заливаю обратно.

Ниже представлены команды для работы с дампом базы данных, создание и восстановление.

 

Создание и восстановление из дампа БД SQLite

Создать dump:

sqlite3 bd.sqlite .dump > dump.sql

Восстановить из dump:

sqlite3 new-bd.db < dump.sql

Работа с одной таблицей

Можно создать только dump определенной таблицы, в данном случаи user:

sqlite new-bd.db
sqlite> .output user.sql
sqlite> .dump user
sqlite> .exit

Отредактировать файл как нужно и залить таблицу обратно, удалив её перед этим из базы:

Удалить таблицу:

#  работа с базой
sqlite new-bd.db 
#  список таблиц
sqlite> .tables
DROP TABLE user;
sqlite> .exit

Восстановить одну таблицу:

sqlite3 new-bd.db < user.sql

Книга: Стандартная библиотека Python3 Справочник с примерами — Даг Хеллман 2-е издание

Книга: Стандартная библиотека Python 3 Справочник с примерами
Книга: Справочник с примерами.
Даг Хеллман «Стандартная библиотека Python 3» Диалектика, 2019 год, 1375 стр., 2-е издание

Книга оказалась очень полезная, в ней можно найти практический всё, что нужно. Подойдет для поиска подходящего модуля из стандартной библиотеки под задачу. Читать её от корки до корки нет смысла, всё же это справочник. Но я узнал из неё много интересного.

Книга огромная, читать (смотреть её) удобно только за столом.

Стандаартная библиотека Python3 Даг Хеллман

Описывает относительно современную версию языка Python3.6 и 3.7. Материал из книги будет актуален ещё несколько лет. Если 2.7 версию использовали столько лет (и будет ещё тянуть старые проекты) то приобретение данный книги, если вы в профессии оправданно.

Оглавление

Глава 1. Текст
Глава 2. Структуры данных
Глава 3. Алгоритмы
Глава 4. Дата и время
Глава 5. Математика
Глава 6. Файловая система
Глава 7. Постоянное хранение и обмен данными
Глава 8. Сжатие и архивирование данных
Глава 9. Криптография
Глава 10. Параллельные вычисления: процессы, потоки и сопрограммы
Глава 11. Обмен данными по сети
Глава 12. Интернет
Глава 13. Электронная почта
Глава 14. Строительные блоки приложений
Глава 15. Интернационализация и локализация приложений
Глава 16. Инструменты разработки
Глава 17. Инструменты среды времени выполнения
Глава 18. Инструменты языка
Глава 19. Модули и пакеты
Приложение А. Замечания относительно портирования программ
Приложение Б. Внешние ресурсы, дополняющие стандартную библиотеку
Указатель модулей Python
Предметный указатель

Пример страницы из книги
Пример страницы из книги