Authentication 使用蝗虫时如何登录Flask应用程序

Authentication 使用蝗虫时如何登录Flask应用程序,authentication,flask,csrf,flask-login,locust,Authentication,Flask,Csrf,Flask Login,Locust,第一次使用蝗虫。我有一个Flask应用程序,需要用户登录才能访问大多数路由。 我无法让蝗虫成功登录到我的烧瓶应用程序 这是我的蝗虫.py文件: 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 i

第一次使用蝗虫。我有一个Flask应用程序,需要用户登录才能访问大多数路由。 我无法让蝗虫成功登录到我的烧瓶应用程序

这是我的蝗虫.py文件:

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
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
当我运行蝗虫时,我得到以下输出:

[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
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
我不担心“UnsecureRequestWarning”,因为这是因为我使用的是自签名证书,并且我已禁用了“self.client.verify=False”验证 csrftoken看起来是正确的

从Flask应用程序本身,我得到以下输出:

[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
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”条件

到目前为止,我已经花了一整天的时间在这上面,阅读文章并尝试了很多事情,比如添加X-CSRFToken头。 我觉得我错过了一些基本的东西,非常感谢你的帮助

谢谢,
WJ

这可能不是蝗虫的问题。您是否尝试过登录并使用诸如Postman或cURL之类的工具获取令牌

好的,我解决了这个问题,所以我想我会和其他遇到这个问题的人分享anwser。正如@user10788336所建议的,它不是一个蝗虫问题

问题是,当发布到烧瓶路线时,表单未被验证,即未设置form.validate

所以,我做了两个改变

我改变了帖子,增加了一个表单项,我称之为testmode,并将该值设置为hocust test

以下是新的蝗虫.py文件:

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
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"
>                                      },
<     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:
我认为这仍然是安全的。。。对此有何想法? 我可能会添加一个配置变量,用于禁用/启用此功能

而且很有效

顺便说一句,蝗虫是可怕的

希望这有帮助

干杯,
WJ

您能否共享form.validate\u on\u submit方法所需/正在验证的代码?登录表单中可能有一个隐藏字段充当动态令牌,并且/或者您缺少一个必填字段。您还可以共享登录表单的HTML源代码吗

我还希望看到您在登录方法中添加一个额外的调试语句,输出CSRF令牌的值,以确保它是有效的,例如

    def login(self):
    print(f"DEBUG: login csrftoken = {self.csrftoken}")
    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}")
我还想知道,当您在没有有效CSRF令牌的情况下提交表单时,是否有任何错误消息。它是否返回200状态码并报告无效令牌

我的猜测是,这与CSRF令牌无效或处理不正确有关

这是旧版本还是自定义版本的Flask登录?在最新版本的Flask登录文档中,我没有看到X-CSRFToken头方法