使用蝗虫时如何登录Flask App [英] How to login to Flask App when using Locust
问题描述
第一次使用蝗虫.我有一个Flask应用,该应用要求用户登录才能访问大多数路线. 我无法让Locust成功登录我的Flask应用.
First time using Locust. I have a Flask App that requires user to login to access most routes. I cant get Locust to successfully login to my Flask App.
这是我的Locust.py文件:
Here is my Locust.py file:
from locust import HttpLocust, TaskSet, task
import re
class UserBehavior(TaskSet):
def on_start(self):
""" on_start is called when a Locust start before any task is scheduled """
self.client.verify = False
self.get_token()
self.login()
def on_stop(self):
""" on_stop is called when the TaskSet is stopping """
self.logout()
def get_token(self):
response = self.client.get("/login")
# Sample string from response:
# <input id="csrf_token" name="csrf_token" type="hidden" value="REDACTED">
self.csrftoken = re.search(' name="csrf_token" .* value="(.+?)"', response.text).group(1)
print(f"DEBUG: self.csrftoken = {self.csrftoken}")
def login(self):
response = self.client.post("/login",
{"email": "REDACTED", "password": "REDACTED"},
headers={"X-CSRFToken": self.csrftoken})
print(f"DEBUG: login response.status_code = {response.status_code}")
def logout(self):
self.client.get("/logout")
@task(5)
def list_domains(self):
response = self.client.get("/domains", headers={"X-CSRFToken": self.csrftoken})
print(f"DEBUG list: response.status_code = {response.status_code}")
class WebsiteUser(HttpLocust):
task_set = UserBehavior
min_wait = 5000
max_wait = 9000
这是我的Flask应用程序的登录功能:(添加了一些调试语句)
Here is the login function of my Flask App: (with a few debug statements added)
@users.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST': ##DEBUG
logging.debug(f"debug0: inside login func with method == POST") ##DEBUG
if current_user.is_authenticated:
return redirect(url_for('main.home'))
form = LoginForm()
if form.validate_on_submit():
logging.debug(f"debug0.1: inside validate_on_submit") ##DEBUG
user = Users.query.filter_by(email=form.email.data).first()
if user and user.check_password(form.password.data):
login_user(user, remember=form.remember.data)
next_page = request.args.get('next')
if not next_page or url_parse(next_page).netloc != '':
next_page = url_for('main.home')
logging.debug(f"debug1: Login was successful") ##DEBUG
return redirect(next_page)
else:
logging.debug(f"debug2: Login failed") ##DEBUG
flash(f'Login unsuccessful. Please check email and password!', 'danger')
logging.debug(f"debug3: the end of login func") ##DEBUG
return render_template('login.html', title='Login', form=form)
运行蝗虫时,得到以下输出:
When i run Locust, I get this output:
[2019-09-16 18:03:06,598] Mac-mini-3.local/INFO/locust.main: Starting web monitor at *:8089
[2019-09-16 18:03:06,598] Mac-mini-3.local/INFO/locust.main: Starting Locust 0.11.0
[2019-09-16 18:03:14,069] Mac-mini-3.local/INFO/locust.runners: Hatching and swarming 2 clients at the rate 1 clients/s...
[2019-09-16 18:03:14,138] Mac-mini-3.local/ERROR/stderr: /Users/myuser/.local/share/virtualenvs/locustio-gB1-mbqd/lib/python3.7/site-packages/urllib3/connectionpool.py:851: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings InsecureRequestWarning)
[2019-09-16 18:03:14,162] Mac-mini-3.local/INFO/stdout: DEBUG: self.csrftoken = REDACTED
[2019-09-16 18:03:14,183] Mac-mini-3.local/INFO/stdout: DEBUG: login response.status_code = 200
[2019-09-16 18:03:14,213] Mac-mini-3.local/INFO/stdout: DEBUG list: response.status_code = 200
[2019-09-16 18:03:15,112] Mac-mini-3.local/INFO/stdout: DEBUG: self.csrftoken = REDACTED
[2019-09-16 18:03:15,137] Mac-mini-3.local/INFO/stdout: DEBUG: login response.status_code = 200
我并不担心"InsecureRequestWarning",因为这是因为我使用的是自签名证书,并且我已禁用了使用"self.client.verify = False"的验证 csrftoken看起来正确.
I'm not concerned about the 'InsecureRequestWarning' as this is because I am using a self signed cert and i have disabled verification with 'self.client.verify = False' The csrftoken looks correct.
从Flask应用程序本身中,我得到以下输出:
From the Flask App itself, I get this output:
DEBUG:user:debug0: inside login func with method == POST
INFO:flask_wtf.csrf:The CSRF token is missing.
DEBUG:user:debug3: the end of login func
DEBUG:user:debug3: the end of login func
DEBUG:user:debug3: the end of login func
DEBUG:user:debug3: the end of login func
因此,它正在使用登录功能(由debug0验证),但没有进入'form.validate_on_submit()'条件.
So, it's hitting the login function (proven by debug0) but it's not getting into the 'form.validate_on_submit()' conditional.
到目前为止,我已经花了一整天的时间,阅读文章并尝试了很多事情,例如添加X-CSRFToken标头. 我觉得我缺少一些基本知识,非常感谢您的帮助.
So far I have spent all day on this, reading articles and trying a lot of things, ie adding the X-CSRFToken headers. I feel I am missing something fundamental, and would really appreciate some help.
谢谢, WJ
推荐答案
好,我解决了这个问题,所以我想与其他任何人分享答案.正如@ user10788336所建议的,这不是蝗虫问题.
Ok, I solved it, so thought I would share the anwser for anyone else that comes across this. As suggested by @user10788336 its is not a Locust issue.
问题在于,当发布到烧瓶路径时,表单没有得到验证(即form.validate()未被设置).
The issue was that when POSTing to the flask route, the form was not being validated (ie form.validate() was not getting set).
所以,我做了两个更改.
So, I made two changes.
1)将POST更改为具有一个附加表单项,我将其称为"test-mode",并将其值设置为"locust-test"
1) changed the POST to have an additional form item which i called "test-mode" and I set the value to "locust-test"
这是新的Locust.py文件:
here is the new Locust.py file:
from locust import HttpLocust, TaskSet, task
import re
class UserBehavior(TaskSet):
def on_start(self):
""" on_start is called when a Locust start before any task is scheduled """
self.client.verify = False
self.get_token()
self.login()
def on_stop(self):
""" on_stop is called when the TaskSet is stopping """
self.logout()
def get_token(self):
response = self.client.get("/login")
# Sample string from response:
# <input id="csrf_token" name="csrf_token" type="hidden" value="REDACTED">
self.csrftoken = re.search(' name="csrf_token" .* value="(.+?)"', response.text).group(1)
print(f"DEBUG: self.csrftoken = {self.csrftoken}")
def login(self):
response = self.client.post("/login",
{"email": "REDACTED",
"password": "REDACTED",
"test-mode": "locust-test"
},
headers={"X-CSRFToken": self.csrftoken})
print(f"DEBUG: login response.status_code = {response.status_code}")
def logout(self):
self.client.get("/logout")
@task(5)
def list_domains(self):
response = self.client.get("/domains", headers={"X-CSRFToken": self.csrftoken})
print(f"DEBUG list: response.status_code = {response.status_code}")
class WebsiteUser(HttpLocust):
task_set = UserBehavior
min_wait = 5000
max_wait = 9000
新旧之间的区别是:
< {"email": "REDACTED", "password": "REDACTED"},
---
> {"email": "REDACTED",
> "password": "REDACTED",
> "test-mode": "locust-test"
> },
2)我更改了Flask应用程序的登录功能: 更改是,我不需要验证表单,因此仅在检测到我正在测试模式下运行时才跳过该表单.
2) I changed my login function the Flask app: The change is that I don't need the form to be validated, so I skip that ONLY when I detect that I am running in test-mode.
这是新的登录功能:
@users.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('main.home'))
form = LoginForm()
# shortcut for Locust testing - need to avoid form.validate() (which is within form.validate_on_submit())
form_is_ok = False
if request.method == 'POST':
if request.form.get('test-mode') == 'locust-test':
form_is_ok = True
else:
form_is_ok = form.validate_on_submit()
if form_is_ok:
logging.debug(f"debug0.1: inside validate_on_submit") # DEBUG
user = Users.query.filter_by(email=form.email.data).first()
if user and user.check_password(form.password.data):
login_user(user, remember=form.remember.data)
next_page = request.args.get('next')
if not next_page or url_parse(next_page).netloc != '':
next_page = url_for('main.home')
logging.debug(f"debug1: Login was successful") # DEBUG
return redirect(next_page)
else:
logging.debug(f"debug2: Login failed") # DEBUG
flash(f'Login unsuccessful. Please check email and password!', 'danger')
logging.debug(f"debug3: the end of login func") # DEBUG
return render_template('login.html', title='Login', form=form)
新旧之间的区别是:
< if form.validate_on_submit():
---
>
> # shortcut for Locust testing - need to avoid form.validate() (which is within form.validate_on_submit())
> form_is_ok = False
> if request.method == 'POST':
> if request.form.get('test-mode') == 'locust-test':
> form_is_ok = True
> else:
> form_is_ok = form.validate_on_submit()
>
> if form_is_ok:
我认为这仍然是安全的……对此有何想法? 我可能会添加一个配置变量,以禁用/启用此功能.
I think this is still secure ... thoughts on that? I might add a config variable, that disables/enables this functionality.
它有效!!!
顺便说一句,蝗虫真棒!
BTW, Locust is awesome!
希望这会有所帮助.
欢呼声, WJ
这篇关于使用蝗虫时如何登录Flask App的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!