为什么Django check_password=True而authenticate=None ? &



我正在尝试在Django中使用尽可能多的内置功能编写一个登录端点的单元测试。

已有测试确认帐户创建端点运行正常。

在登录视图中,check_password()函数返回的是True,而authenticate()函数返回的是None

使用check_password()函数是否安全?

否则,我如何更新这段代码来使用authenticate()函数?

accounts.py

class Account(AbstractUser):
username = models.CharField(max_length=150, unique=True, null=False, default='')
password = models.CharField(max_length=100)
...
REQUIRED_FIELDS = ['username', 'password']
class Meta:
app_label = 'accounts'
db_table = 'accounts_account'
objects = models.Manager()

test_login.py

def test_login(self):
# Create account
request_create = self.factory.post('/accounts/account',
self.request_data,
content_type='application/json')
view = AccountView.as_view()
response_create = view(request_create)
# Login account
request_login = self.factory.post('/accounts/login',
self.request_data,
content_type='application/json')
view = LoginView.as_view()
response = view(request_login)

views.py

class LoginView(View):
def post(self, request):
r = json.loads(request.body)
username = r.get('username')
password = r.get('password')
cp = check_password(password, Account.objects.get(username=username).password)
user = authenticate(username=username, password=password)

注:我已经检查了这个线程,is_active被设置为true。

安全。主要区别在于,通过使用check_password(),您将从身份验证后端手动检查User,因此您必须检索User对象并将其密码与纯文本进行比较,就像在:

所做的那样
check_password(password, Account.objects.get(username=username).password)

然而,使用authenticate()可以根据多个身份验证后端检查凭据。这意味着使用前者,您不能将应用程序与其他身份验证源挂钩

您在tests.pyviews.py中缺少一些代码。话虽如此,这里是这个LoginView的完整测试:

tests.py

class TestClientLogin(TestCase):
def setUp(self):
User = get_user_model()
self.factory = RequestFactory()
self.user = User.objects.create_user(
username='test_user',
email='test_user@example.com',
password='super_secret'
)

def test_user_login(self):
request_data = {'username': 'test_user', 'password': 'super_secret'}
request = self.factory.post(
'/accounts/login/', 
request_data , 
content_type='application/json'
)
response = LoginView.as_view()(request)
data = json.loads(response.content)
self.assertEqual(self.user.username, data['username'])
self.assertEqual(response.status_code, 200)

views.py

class LoginView(View):
def post(self, request):
data = json.loads(request.body)
username = data.get('username')
password = data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
return JsonResponse({'username': user.username})
else:
return JsonResponse({'username': None})

如果你想使用尽可能多的内置功能:

<标题>settings.py:
AUTH_USER_MODEL = 'accounts.Account'
<标题>账户/models.py:
class Account(AbstractUser):
# you dont need to define username or password again
...
REQUIRED_FIELDS = ['username', 'password']
class Meta:
# you don't need to define default app_label, db_table
objects = UserManager()  # otherwise don't work "python manage.py createsuperuser"
<标题>账户/views.py:
from django.contrib.auth.views import LoginView

class ClientLogin(LoginView):
pass
<标题>账户/tests.py:
from django.test import TestCase, Client
from django.utils.crypto import get_random_string
class TestClientLogin(TestCase):
def setUp(self):
User = get_user_model()
self.username, self.password = get_random_string(20), get_random_string(20)  # don't use constants in tests
self.user = User.objects.create_user(username=self.username, password=self.password )
def test_user_login(self):
request_data = {'username': self.username, 'password': self.password}
response = Client().post('/accounts/login/', request_data)
self.assertEqual(response.status_code, 302)
<标题>

但是:你不需要测试ClientLogin,你没有任何代码在视图中

相关内容

  • 没有找到相关文章

最新更新