python CSRF令牌似乎妨碍了

tjvv9vkg  于 2023-03-16  发布在  Python
关注(0)|答案(1)|浏览(155)

CSRF令牌 * 似乎 * 妨碍了

我正在为我的应用程序编写django测试,我的一个视图允许用户“喜欢”其他用户的帖子。但是测试失败了,问题 * 似乎 * 是没有CSRF令牌,但我不确定是否是真的。POST数据不被视图使用,它只使用url数据,我这么说的唯一原因是因为我写的其他测试也有类似的问题,并且解决了这个问题,但是我尝试的任何东西都不起作用
下面是我测试:

from django.test import TestCase, Client
from django.utils import timezone
from django.contrib.auth import get_user_model
from django.contrib.auth.models import User
from django.middleware.csrf import get_token

from .views import update
from .models import Post, Like

def setUp(self):
        # creates a user and logs into the client
        self.user = User.objects.create_user(username='testuser', password='testpass')
        self.client = Client()
        self.client.force_login(self.user)

--- some code ommited ---

def test_like_view(self):
        # make a post
        p1 = Post.objects.create(title='title', body='body', published_date=timezone.now(), created_by=self.user)

        # get CSRF token
        response = self.client.get(f'/{p1.id}/update/')
        csrf_token = response.cookies['csrftoken'].value

        # send POST request with CSRF token
        response = self.client.post(f'/{p1.id}/like/', {'csrfmiddlewaretoken': csrf_token})

        # check that the response status code is 302, indicating a redirect
        self.assertEqual(response.status_code, 302)

        # check that a Like object was created
        self.assertTrue(Like.objects.filter(post=p1).exists())

这是我的观点

from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.utils import timezone
from django.db.models import Count
from django.contrib.auth.decorators import login_required

from .models import Post, Like

--- some code ommited ---

@login_required
def like(request, pk):
    #users cannot like posts that they have allready liked in the past
    post = Post.objects.get(id=pk)
    
    l = Like(users = request.user, posts = post)
    all_likes = Like.objects.all()
    for like in all_likes:
        if l.users == like.users and l.posts == like.posts:
            return HttpResponseRedirect('..')
    l.save()
    return HttpResponseRedirect('..')

我手动测试了视图,我知道它工作的事实,当使用microsoft edge中的dev工具时,我看到一个csrf令牌正在传输。

cvxl0en2

cvxl0en21#

拥有一个csrf_token和登录是两件不同的事情。匿名用户仍然可以获得一个令牌,这样服务器就可以识别客户端。
我建议只使用self.client.login()命令,我已经使用它取得了很多成功,而且我从来没有手动为任何POST或GET提供令牌

这是我格式化测试和登录的一般方式:
  • 我把它们拆开,扔进一些额外的Assert,给予你一些想法:)
from django.http import HttpResponseRedirect
from django.utils import timezone
from django.shortcuts import render
from django.db.models import Count
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required

from .models import Like, Post

class LikeCase(TestCase):
    def setUp(self):
        # Note:
        #   Setup is ran for every `def test_`, so you can change the Post obj
        #   and the entire db will be rolled back / recreated for the next one
        u0 = User.objects.create(username='test_user')
        u0.set_password('test')
        u0.save()

        self.p1 = Post.objects.create(
            title='title',
            body='body',
            published_date=timezone.now(),
            created_by=u0
        )

    def test_update_get(self):
        self.client.login(username='test_user', password='test')

        response = self.client.get(f'/{self.p1.id}/update/')
        # Basic Attributes
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response['content-type'], 'text/html; charset=utf-8')
        self.assertTemplateUsed(response, '/path/to/my/template.html')
        # Specific Attibutes (vars passed to template)
        self.assertEqual(response.context['post_obj'], self.p1)

    def test_like_post(self):
        self.client.login(username='test_user', password='test')

        # Should auto-send token
        response = self.client.post(f'/{self.p1.id}/like/')

        # Test correct redirect
        self.assertRedirects(
            response,
            f"/my/redirect/url",
            status_code=302,
            target_status_code=200,
            fetch_redirect_response=False
        )

        # Test object existence and fields
        like_obj = Like.objects.filter(post=self.p1).first()
        self.assertIsNotNone(like_obj)
        self.assertEqual(like_obj.post, self.p1)
        self.assertEqual(like_obj.user.username, 'test_user')

    # Check for Login Decorator - both requests should be denied
    def test_like_anonymous(self):
        url = f'/{self.p1.id}/like/'
        with self.subTest('Anonymous GET'):
            response = self.client.get(url)
            self.assertEqual(response.status_code, 302)
        with self.subTest('Anonymous POST'):
            response = self.client.post(url)
            # Note: Redirect or Forbidden
            self.assertTrue(response.status_code in (403, 302))

我总是通过def test_()登录,因为我总是测试登录装饰器是否存在。如果我在安装过程中登录,我将不得不注销。我也只是使匿名测试成为一个函数,并只传递URL和self(输入较少)

相关问题