如何在请求上下文之外伪造JWT授权并获得当前身份?

时间:2019-04-19 09:30:36

标签: python flask pytest flask-jwt-extended

我正在使用JWT授权创建Flask应用,并尝试使用PyTest测试服务。

我已成功将测试添加到端点,但是当我尝试为某些功能添加单元测试时,由于flask_jwt_extended.get_current_user()返回None,所以无法访问当前用户。

这是一个简单的例子:

@api.route('/listings', methods=['POST'])
@jwt_required
def create_listing():
    payload = request.json
    listing = listing_svc.create(payload)
    return listing


def create(payload):
    listing = ListingSchema().load(payload, db.session).data


class ListingSchema(ModelSchema):
    id = field_for(Project, 'id', dump_only=True)
    creator_user_id = field_for(Project, 'creator_user_id')
    # ...

    @pre_load
    def set_creator_id(self, data):
        current_user = flask_jwt_extended.get_current_user()
        data['creator_user_id'] = current_user.id

当我使用app_context授权并发送请求时,它可以工作:

with client.application.app_context():
    rv = client.post('/listings',
        # ...
    )

但是我需要测试create功能而不向客户端发送请求。在这种情况下,flask_jwt_extended.get_current_user()返回None,所以我认为我应该在运行此功能之前以某种方式设置请求上下文。

我试图做到这一点...

fake_payload = {}
with client.application.test_request_context('/listings', headers={'Authorization': 'Bearer ' + access_token}):
    create(fake_payload)

但仍然获得current_user的是None

这是我获取令牌的方式:

def login(email, password):
    user = get_by_email(email)
    if user and check_password_hash(user.password, password):
        return access_token = flask_jwt_extended.create_access_token(identity=email)

3 个答案:

答案 0 :(得分:0)

如果您确实要进行单元测试,则需要一次对一个功能进行单元测试。我认为这是真正的测试驱动开发。因此,首先编写用于创建的测试,然后加载。使用修补程序模拟对其他函数的调用功能。

答案 1 :(得分:0)

如果您正在编写单元测试,则使用模拟可能会有所帮助。对于带有flask-jwt-extended的jwt授权,您可以修补jwt_required decorator中调用的verify_jwt_in_request方法。然后,您也可以修补get_jwt_identity函数以返回测试用户名。例如:

from unittest.mock import patch


@patch('path.to.some.code.get_jwt_identity')
@patch('flask_jwt_extended.view_decorators.verify_jwt_in_request')
def test_some_code(mock_jwt_required, mock_jwt_identity):
    mock_jwt_identity.return_value = 'user1'

    # Test jwt protected endpoint

注意:此修补程序特定于最新的软件包版本flask-jwt-extended == 3.21.0。该代码可能会随新版本而更改。

答案 2 :(得分:0)

很久以前的问题,但这是更多读者的解决方案。

您需要先激活app_context,然后再激活request_context,最后调用装饰器正在调用的函数,即 verify_jwt_in_request


fake_payload = {}
with client.application.app_context():
    with client.application.test_request_context('/listings', headers={'Authorization': 'Bearer ' + access_token}):
        verify_jwt_in_request()
        create(fake_payload)

现在您已设置了current_user