Flask disable CSRF in unittest

时光怂恿深爱的人放手 提交于 2019-12-10 13:29:20

问题


In my projects __init__.py I have this:

app = Flask(__name__)
app.config.from_object('config')
CsrfProtect(app)
db = SQLAlchemy(app)

My development config file looks like:

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

And in my unittest setUp I have this:

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

In theory, setting WTF_CSRF_ENABLED to False here should prevent CSRF for the unit tests, however I'm still getting CSRF errors if I do a POST while unit testing. I think it is because I have already called CsrfProtect(app) while WTF_CSRF_ENABLED is True (when I import app, it is called). If I set WTF_CSRF_ENABLED = False in the config file, it works as expected.

Is there anyway I can disable CSRF after it has already been enabled? Or am I barking up the wrong tree here?


回答1:


Looking at the code for csrf_protect, it checks app.config['WTF_CSRF_METHODS'] every time a request comes in to see if this request type should be CSRF protected. By default the protected methods are:

app.config.setdefault('WTF_CSRF_METHODS', ['POST', 'PUT', 'PATCH'])

Because it actually checks the app.config every time, simply changing this to an empty list in my unit tests setUp resolves the issue:

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

Alternetly, it does register the csrf protection with app.before_request(), so I think it may be possible to unregister it by modifying the before request functions. But I think going that route would be more likely to see problems on future updates.




回答2:


You can disable it using the config variable WTF_CSRF_ENABLED,

for example

class TestConfig(Config):
    TESTING = True
    WTF_CSRF_ENABLED = False
    ...

or app.config['WTF_CSRF_ENABLED'] = False

See also flask-WTF documentation




回答3:


It wasn't too hard to keep the csrf_token if that is an option. I was able to successfully log into an application that used a csrf_token using some regular expressions and using the login function that is found in the Flask docs about testing.

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)

So what I have done here is made the csrf_token be apart of the second capture group. This could easily be used to find a token all over the application.



来源:https://stackoverflow.com/questions/38624060/flask-disable-csrf-in-unittest

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!