错误请求 |未找到 CSRF 令牌 | Flask WTF 的 CSRF 处理

Bad Request | CSRF Token Not Found | CSRF Handling for Flask WTF

问题

我在几个简单的志愿组织工作,帮助管理和 运行 活动,但我们需要一个系统来跟踪人们的酬金和生产力跟踪时间。我认为这是学习一些 Web 开发并开始使用 Flask 应用程序的好机会,因为它显然比 Django 更简单,我不知道 javascript。部署应用程序修复错误等,但现在有人在提交登录表单后使用 this picture 登录后回来。

“错误请求 CSRF 令牌丢失”。
“错误请求 CSRF 令牌不匹配”。
“错误请求 CSRF 令牌已过期”。

这些是我设法得到的错误消息,除非我实施错误,否则没有在线解决方案可以为我修复它们。我什至没有在 gunicorn 日志中收到错误消息,我只是加载了该图像。
经过这么长时间的调试,让它开始工作并自豪地展示它,我感到非常沮丧,现在它做到了,所以也许是那些有偏见的挫败感阻止了我聪明地找到解决方案

代码

我有我的隐藏标签,所以 csrf 应该不会丢失 /webapp/website/templates/login.html

<body>
    {%extends 'base.html'%}
    {% block content %}
    <div class="shadow p-3 mb-5 bg-body rounded">
    <h3 align="center">Login</h3>
    <form method="POST">
        {{ form.hidden_tag() }}
        
        {{ form.email.label(class='form-label')}}
        {{ form.email(class='form-control')}}
        <br/>
        {{ form.password.label(class='form-label')}}
        {{ form.password(class='form-control')}}
        <br/>
        {{ form.submit(class='btn btn-danger')}}
    </form>
    </div>
    {% endblock %}
</body>
</html>

.env

SECRET_KEY='iremovedtheactualone'
DEV_DATABASE_URI='mysql+pymysql://root:root@localhost/main'
PROD_DATABASE_URI='mysql+pymysql://user:password@ip/db'
SERVER_NAME='websitename.com'

www 到非 www nginx 重定向不起作用我的应用程序在 www 上不起作用是我的一个朋友概述的另一个问题 here

/webapp/website/config.py

from os import environ, path
from dotenv import load_dotenv

DB_NAME = "main"

class Config:
    """Base config."""
    #SESSION_COOKIE_NAME = environ.get('SESSION_COOKIE_NAME')
    MAX_CONTENT_LENGTH = 16*1000*1000
    RECEIPT_FOLDER = '..\assets\receipts'
    UPLOAD_EXTENSIONS = ['.jpg', '.png', '.pdf']
    STATIC_FOLDER = 'static'
    TEMPLATES_FOLDER = 'templates'
    SESSION_COOKIE_SECURE = True

class ProdConfig(Config):
    basedir = path.abspath(path.dirname(__file__))
    load_dotenv('/home/sai/.env')
    env_dict = dict(environ)
    FLASK_ENV = 'production'
    DEBUG = False
    TESTING = False
    SQLALCHEMY_DATABASE_URI = environ.get('PROD_DATABASE_URI')
    SECRET_KEY = environ.get('SECRET_KEY')
    SERVER_NAME = environ.get('SERVER_NAME')
    ...

/webapp/website.__init__.py

def create_app(name):
    #Flask Instance
    app = Flask(__name__)
    app.config.from_object(config.ProdConfig)

    if name  != '__main__':
        gunicorn_logger=logging.getLogger('gunicorn.error')
        app.logger.handlers = gunicorn_logger.handlers
        app.logger.setLevel(gunicorn_logger.level)

    db.init_app(app)
    migrate.init_app(app, db)
    csrf.init_app(app)
    ...

/webapp/website.auth.py

@auth.route('/login', methods=['GET', 'POST'])
def login():
    current_app.logger.info('enter login')
    ...
    if form.validate_on_submit():
        current_app.logger.info('enter submit')
        ...
        user = Users.query.filter_by(email=email).first()
        if user:
            current_app.logger.info('enter user')
            if check_password_hash(user.password_hash, password):
                current_app.logger.info('enter password')

                flash('Logged in successfully!', category='success')
                login_user(user, remember=True)
                form.email.data = ''
                form.password.data = ''
                
                #Default
                return redirect('/shift_add')

                # Method Two
                next = request.args.get('next')
                #current_app.logger.info(next)
                #if not is_safe_url(next):
                #    return abort(400)
                #else:
                #    return redirect(next or url_for('views.home'))

                # Method Three
                #next_url = request.form.get("next")
                #if next_url:
                #    return redirect(next_url)
                #return redirect(url_for('views.home') or next)

                # Method Four
                # return redirect(str(request.args.get("next")) or "/shift_add")
            else:
                ...
        else:
            ...

        ...
    else:
        current_app.logger.info('errors: ')
        current_app.logger.info(form.errors)

    return render_template('/user/login.html', form=form)

主要问题

如何解决CSRF有时丢失、过期或不匹配的问题。 None 这些错误会在我的日志中引发任何错误,除非我没有正确显示,但我无法弄清楚为什么每个错误都会发生。现在,我的 chrome 浏览器显示缺少令牌,firefox 显示已过期,而 iphone 上的 safari 显示不匹配。

同样令人信服的是,我是如何配置 CSRF 错误的?我错过了什么?我不仅想学习如何解决这些问题,还想学习为什么会发生这些问题以及继续前进的最佳实践。谢谢!

尝试的解决方案

Clearing cookies解决CSRF token不匹配问题。我在 chrome 上尝试 运行 隐身站点,但我发现 CSRF 令牌丢失了,这是我的 chrome 问题。 Firefox(我的问题是它说已过期)但在隐身模式下也说令牌丢失了。

Apparently a bug in webkit browsers 我不是 运行 docker,也许这个解决方案只是在我的脑海中。

情况并非如此,因为我之前已经成功登录并且我没有发送任何大的东西。

你总是可以只使用 csrf_exempt 装饰器。

虽然这不是一个好的做法

This 答案救了我的命,经过 DAYS 的研究后我才在这里找到它。