Flask 烧瓶禁用单元测试中的CSRF

Flask 烧瓶禁用单元测试中的CSRF,flask,flask-wtforms,Flask,Flask Wtforms,在我的projects\uuuu init\uuuuuuy.py中,我有: app = Flask(__name__) app.config.from_object('config') CsrfProtect(app) db = SQLAlchemy(app) from project import app, db class ExampleTest(unittest.TestCase): def setUp(self): app.config['TESTING'] =

在我的projects\uuuu init\uuuuuuy.py中,我有:

app = Flask(__name__)
app.config.from_object('config')
CsrfProtect(app)
db = SQLAlchemy(app)
from project import app, db

class ExampleTest(unittest.TestCase):
   def setUp(self):
        app.config['TESTING'] = True
        app.config['WTF_CSRF_ENABLED'] = False
        app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
        self.app = app.test_client()
        db.create_all()
我的开发配置文件如下所示:

import os
basedir = os.path.abspath(os.path.dirname(__file__))

DEBUG = True
WTF_CSRF_ENABLED = True
SECRET_KEY = 'supersecretkey'
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'project.db')
SQLALCHEMY_TRACK_MODIFICATIONS = False
在我的unittest设置中,我有:

app = Flask(__name__)
app.config.from_object('config')
CsrfProtect(app)
db = SQLAlchemy(app)
from project import app, db

class ExampleTest(unittest.TestCase):
   def setUp(self):
        app.config['TESTING'] = True
        app.config['WTF_CSRF_ENABLED'] = False
        app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
        self.app = app.test_client()
        db.create_all()
理论上,这里将WTF_CSRF_ENABLED设置为False应该可以防止单元测试中出现CSRF,但是如果我在单元测试时发布帖子,仍然会出现CSRF错误。我想这是因为我已经调用了CsrfProtect(app),而WTF_CSRF_ENABLED是真的(当我导入app时,它被调用)。如果我在配置文件中设置WTF_CSRF_ENABLED=False,它将按预期工作


在CSRF已经启用后,我是否可以禁用它?还是我在这里查错了树?

查看csrf\u protect的代码,每次请求进来时,它都会检查app.config['WTF\u csrf\u METHODS',以确定该请求类型是否应该受到csrf保护。默认情况下,受保护的方法是:

app.config.setdefault('WTF_CSRF_METHODS', ['POST', 'PUT', 'PATCH'])
因为它实际上每次都会检查app.config,所以在“我的单元测试”设置中将其更改为空列表即可解决此问题:

from project import app, db

class ExampleTest(unittest.TestCase):
   def setUp(self):
        app.config['TESTING'] = True
        app.config['WTF_CSRF_METHODS'] = []  # This is the magic
        app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite://'
        self.app = app.test_client()
        db.create_all()

另外,它确实在app.before_request()中注册了csrf保护,因此我认为可以通过修改。但我认为这样做更有可能在将来的更新中看到问题。

如果可以选择,保留
csrf\u令牌并不难。我能够成功地登录到一个应用程序,该应用程序使用了
csrf_令牌
,使用了一些正则表达式,并使用了about测试中的login函数

def login(self, username, password):
    rv = self.client.get('/login')
    m = re.search(b'(<input id="csrf_token" name="csrf_token" type="hidden" value=")([-A-Za-z.0-9]+)', rv.data)

    return self.client.post('/login', data=dict(
        userName=username,
        password=password,
        csrf_token=m.group(2).decode("utf-8")
    ), follow_redirects=True)
def登录(自我、用户名、密码):
rv=self.client.get('/login')

m=re.search(b’(您可以使用配置变量
WTF\u CSRF\u ENABLED
禁用它

比如说

class TestConfig(Config):
    TESTING = True
    WTF_CSRF_ENABLED = False
    ...
app.config['WTF\u CSRF\u ENABLED']=False


另请参见

我认为,一旦您导入应用程序,该代码将运行,因此它将使用您的默认配置运行,因此,在您进行测试之后,您是否过度使用了配置也无关紧要。是的,这也是我的想法。我希望有某种方法可以在事后禁用它,可能不是通过app.config,而是类似于StopCsrfP的方式rotect(应用程序)或者别的什么。但这可能是一厢情愿的想法。我想最简单的解决办法是在测试时禁用CSRF。我可以这样做,但我担心这可能会打乱任何集成测试。我可能需要记住在运行单元测试时来回更改配置文件,或者冒着看不到真正的CSRF错误的风险在开发时(忘记在jinja模板或其他东西中放置隐藏的_标记)。嗯…创建一个自定义类扩展单元测试并覆盖此配置并在其他测试类中使用此正则表达式对我来说失败了很多。更新并持续工作:
m=re.search(b'',rv.data)
然后只解码
m.group(1).解码(“utf-8”)
因为没有理由捕获第一个组。您缺少下划线,但没有理由定义有效字符,因为最后的
会正确终止捕获组。我更愿意关闭csrf,但这似乎会导致模板现在失败。我根本不明白为什么。