django-rest使用自定义身份验证测试视图

时间:2017-05-25 10:50:16

标签: django authentication django-rest-framework

我尝试测试具有自定义身份验证的视图,主要是因为主身份验证基于外部登录注销系统,使用Redis作为数据库来存储会话。

Auth类正在检查请求中的会话ID,是否与Redis中的相同 - 如果是,则成功。

我的自定义authentication.py看起来像:

from django.utils.six import BytesIO

from rest_framework import authentication
from rest_framework import exceptions

from rest_framework.parsers import JSONParser

import redis


class RedisAuthentication(authentication.BaseAuthentication):
    def authenticate(self, request):

    print(request.META)
    token = request.META['HTTP_X_AUTH_TOKEN']
    redis_host = "REDIS_IP_ADRESS"
    redis_db = redis.StrictRedis(host=redis_host)
    user_data = redis_db.get("user_feature:{}".format(token))
    if user_data is None:
        raise exceptions.AuthenticationFailed('No such user or session expired')

    try:
        stream = BytesIO(user_data)  # Decode byte type
        data = JSONParser(stream)  # Parse bytes class and return dict
        current_user_id = data['currentUserId']
        request.session['user_id'] = current_user_id
    except Exception as e:
        print(e)

    return (user_data, None)

和我的views.py看起来像:

@api_view(['GET', 'POST'])
@authentication_classes((RedisAuthentication, ))
def task_list(request):
    if request.method == 'GET':
        paginator = PageNumberPagination()
        task_list = Task.objects.all()
        result_page = paginator.paginate_queryset(task_list, request)
        serializer = TaskSerializer(result_page, many=True)
        return paginator.get_paginated_response(serializer.data)

    elif request.method == 'POST':
        serializer = PostTaskSerializer(data=request.data)
        if serializer.is_valid():
            user_id = request.session.get('user_id')
            serializer.save(owner_id=user_id)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

手动测试通过,但我添加的authentication.py后我的当前pytests失败,并且不知道我如何正确修复它 - 尝试强制使用auth,但没有成功。 我认为其中一个解决方案是使用fakeredis来模拟真正的redis。问题是,这种测试应该如何?

您可以在这里找到的测试示例:

@pytest.mark.webtest
class TestListView(TestCase):
    def setUp(self):
        self.client = APIClient()
    def test_view_url_accessible_by_name(self):
        response = self.client.get(
            reverse('task_list')
        )
        assert response.status_code == status.HTTP_200_OK

@pytest.mark.webtest
class TestCreateTask(TestCase):
    def setUp(self):
        self.client = APIClient()
        self.user = User.objects.create_user(username='admin', email='xx', password='xx')
    def test_create(self):
        data = {some_data}
        self.client.login(username='xx', password='xx')
        response = self.client.post(
            reverse('task_list'),
            data,
            format='json')
        assert response.status_code == status.HTTP_201_CREATED
        self.client.logout()

提前感谢您的帮助!

1 个答案:

答案 0 :(得分:0)

我设法使用ock.patch装饰器-https://docs.python.org/3.5/library/unittest.mock-examples.html#patch-decorators模拟了整个redis身份验证。

将导入修补程序放置到嘲笑装饰器中时,请勿在存储Redis代码的位置插入模块绝对路径,而要在将Redis代码作为模块导入并使用的路径插入。

我的测试现在看起来像这样

@mock.patch('api.views.RedisAuthentication.authenticate')
def test_view_url_accessible_by_name(self, mock_redis_auth):

    data = {"foo": 1, "currentUserId": 2, "bar": 3}
    mock_redis_auth.return_value = (data, None)

    response = self.client.get(
        reverse('task_list'),
        HTTP_X_AUTH_TOKEN='foo'
    )
    assert response.status_code == status.HTTP_200_OK