feat: update login api
This commit is contained in:
+109
-9
@@ -5,6 +5,7 @@ from unittest.mock import patch
|
||||
from django.core.cache import cache
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from apps.user.models import User
|
||||
from apps.user.throttling import SmsPhoneMinuteThrottle, RegisterIpThrottle
|
||||
from .conftest import (
|
||||
CacheTestCase,
|
||||
@@ -14,7 +15,7 @@ from .conftest import (
|
||||
USER_LIST_URL, user_detail_url,
|
||||
DEFAULT_INSTITUTION_CODE, DEFAULT_INSTITUTION_NAME,
|
||||
inject_sms_code, create_test_user, get_auth_client, get_tokens,
|
||||
create_teacher_student_relation,
|
||||
create_teacher_student_relation, ensure_institution,
|
||||
)
|
||||
|
||||
|
||||
@@ -55,10 +56,16 @@ class UserNegativeTest(CacheTestCase):
|
||||
|
||||
# ── 字段校验 ─────────────────────────────────────────────────────────
|
||||
|
||||
def _admin_client(self, phone='13800000001'):
|
||||
"""返回携带超级管理员 JWT 的客户端(U2 代注册需管理员身份)。"""
|
||||
admin = create_test_user(phone=phone, password='Admin123', role_type='super_admin')
|
||||
return get_auth_client(admin)
|
||||
|
||||
def test_register_invalid_phone_400(self):
|
||||
"""N4: 手机号格式不合法 → 400 SMS_INVALID_PHONE"""
|
||||
client = self._admin_client()
|
||||
with patch.object(RegisterIpThrottle, 'allow_request', return_value=True):
|
||||
resp = self.client.post(USER_REGISTER_URL, {
|
||||
resp = client.post(USER_REGISTER_URL, {
|
||||
'phone': '123',
|
||||
'real_name': '测试',
|
||||
'institution_code': DEFAULT_INSTITUTION_CODE,
|
||||
@@ -70,10 +77,12 @@ class UserNegativeTest(CacheTestCase):
|
||||
def test_register_missing_institution_400(self):
|
||||
"""N5: 注册缺少机构编码 → 400 USER_INSTITUTION_CODE_REQUIRED"""
|
||||
phone = '13800001002'
|
||||
client = self._admin_client()
|
||||
with patch.object(RegisterIpThrottle, 'allow_request', return_value=True):
|
||||
resp = self.client.post(USER_REGISTER_URL, {
|
||||
resp = client.post(USER_REGISTER_URL, {
|
||||
'phone': phone,
|
||||
'real_name': '测试缺机构',
|
||||
'role_type': 'student',
|
||||
})
|
||||
self.assertEqual(resp.status_code, 400, resp.content)
|
||||
self.assertEqual(resp.json()['code'], 'USER_INSTITUTION_CODE_REQUIRED')
|
||||
@@ -82,8 +91,9 @@ class UserNegativeTest(CacheTestCase):
|
||||
"""N6: 已注册手机号再注册 → 400 AUTH_PHONE_REGISTERED"""
|
||||
phone = '13800001003'
|
||||
create_test_user(phone=phone)
|
||||
client = self._admin_client()
|
||||
with patch.object(RegisterIpThrottle, 'allow_request', return_value=True):
|
||||
resp = self.client.post(USER_REGISTER_URL, {
|
||||
resp = client.post(USER_REGISTER_URL, {
|
||||
'phone': phone,
|
||||
'real_name': '重复注册',
|
||||
'institution_code': DEFAULT_INSTITUTION_CODE,
|
||||
@@ -92,12 +102,102 @@ class UserNegativeTest(CacheTestCase):
|
||||
self.assertEqual(resp.status_code, 400, resp.content)
|
||||
self.assertEqual(resp.json()['code'], 'AUTH_PHONE_REGISTERED')
|
||||
|
||||
# ── 代注册权限 ───────────────────────────────────────────────────────
|
||||
|
||||
def test_register_unauth_401(self):
|
||||
"""N-REG1: 未登录调用代注册 → 401"""
|
||||
with patch.object(RegisterIpThrottle, 'allow_request', return_value=True):
|
||||
resp = self.client.post(USER_REGISTER_URL, {
|
||||
'phone': '13800001007', 'real_name': '匿名',
|
||||
'institution_code': DEFAULT_INSTITUTION_CODE,
|
||||
'institution_name': DEFAULT_INSTITUTION_NAME,
|
||||
})
|
||||
self.assertEqual(resp.status_code, 401, resp.content)
|
||||
|
||||
def test_register_non_admin_403(self):
|
||||
"""N-REG2: 非管理员(doctor)调用代注册 → 403 USER_NO_REGISTER_PERMISSION"""
|
||||
doctor = create_test_user(phone='13800001008', password='Doc12345', role_type='doctor')
|
||||
client = get_auth_client(doctor)
|
||||
with patch.object(RegisterIpThrottle, 'allow_request', return_value=True):
|
||||
resp = client.post(USER_REGISTER_URL, {
|
||||
'phone': '13800001009', 'real_name': '被注册',
|
||||
'role_type': 'student',
|
||||
'institution_code': DEFAULT_INSTITUTION_CODE,
|
||||
'institution_name': DEFAULT_INSTITUTION_NAME,
|
||||
})
|
||||
self.assertEqual(resp.status_code, 403, resp.content)
|
||||
self.assertEqual(resp.json()['code'], 'USER_NO_REGISTER_PERMISSION')
|
||||
|
||||
def test_register_hospital_admin_cannot_create_super_admin_403(self):
|
||||
"""N-REG3: 医院管理员创建超级管理员 → 403 USER_NO_REGISTER_ROLE_PERMISSION"""
|
||||
hadmin = create_test_user(phone='13800001010', password='Hosp1234', role_type='hospital_admin')
|
||||
client = get_auth_client(hadmin)
|
||||
with patch.object(RegisterIpThrottle, 'allow_request', return_value=True):
|
||||
resp = client.post(USER_REGISTER_URL, {
|
||||
'phone': '13800001011', 'real_name': '超管',
|
||||
'role_type': 'super_admin',
|
||||
'institution_code': DEFAULT_INSTITUTION_CODE,
|
||||
'institution_name': DEFAULT_INSTITUTION_NAME,
|
||||
})
|
||||
self.assertEqual(resp.status_code, 403, resp.content)
|
||||
self.assertEqual(resp.json()['code'], 'USER_NO_REGISTER_ROLE_PERMISSION')
|
||||
|
||||
def test_register_hospital_admin_creates_student_ok(self):
|
||||
"""N-REG4: 医院管理员在本机构创建学生 → 201(新用户机构=管理员机构)"""
|
||||
inst = ensure_institution(name=DEFAULT_INSTITUTION_NAME, code=DEFAULT_INSTITUTION_CODE)
|
||||
hadmin = create_test_user(phone='13800001012', password='Hosp1234',
|
||||
role_type='hospital_admin', institution=inst)
|
||||
client = get_auth_client(hadmin)
|
||||
with patch.object(RegisterIpThrottle, 'allow_request', return_value=True):
|
||||
resp = client.post(USER_REGISTER_URL, {
|
||||
'phone': '13800001013', 'real_name': '新学生',
|
||||
'role_type': 'student',
|
||||
'institution_code': DEFAULT_INSTITUTION_CODE,
|
||||
'institution_name': DEFAULT_INSTITUTION_NAME,
|
||||
})
|
||||
self.assertEqual(resp.status_code, 201, resp.content)
|
||||
# 新用户机构应等于医院管理员所属机构
|
||||
new_user = User.objects.get(phone='13800001013')
|
||||
self.assertEqual(new_user.institution_id, inst.id)
|
||||
|
||||
def test_register_hospital_admin_cross_institution_403(self):
|
||||
"""N-REG5: 医院管理员跨机构建账号 → 403 USER_INSTITUTION_SCOPE_FORBIDDEN"""
|
||||
inst_a = ensure_institution(name='医院A', code='HOSP-A')
|
||||
ensure_institution(name='医院B', code='HOSP-B')
|
||||
hadmin = create_test_user(phone='13800001014', password='Hosp1234',
|
||||
role_type='hospital_admin', institution=inst_a)
|
||||
client = get_auth_client(hadmin)
|
||||
with patch.object(RegisterIpThrottle, 'allow_request', return_value=True):
|
||||
resp = client.post(USER_REGISTER_URL, {
|
||||
'phone': '13800001015', 'real_name': '跨机构学生',
|
||||
'role_type': 'student',
|
||||
'institution_code': 'HOSP-B',
|
||||
'institution_name': '医院B',
|
||||
})
|
||||
self.assertEqual(resp.status_code, 403, resp.content)
|
||||
self.assertEqual(resp.json()['code'], 'USER_INSTITUTION_SCOPE_FORBIDDEN')
|
||||
|
||||
def test_register_hospital_admin_no_institution_403(self):
|
||||
"""N-REG6: 无所属机构的医院管理员代注册 → 403 USER_NO_REGISTER_INSTITUTION"""
|
||||
hadmin = create_test_user(phone='13800001016', password='Hosp1234',
|
||||
role_type='hospital_admin') # institution=None
|
||||
client = get_auth_client(hadmin)
|
||||
with patch.object(RegisterIpThrottle, 'allow_request', return_value=True):
|
||||
resp = client.post(USER_REGISTER_URL, {
|
||||
'phone': '13800001017', 'real_name': '无机构学生',
|
||||
'role_type': 'student',
|
||||
'institution_code': DEFAULT_INSTITUTION_CODE,
|
||||
'institution_name': DEFAULT_INSTITUTION_NAME,
|
||||
})
|
||||
self.assertEqual(resp.status_code, 403, resp.content)
|
||||
self.assertEqual(resp.json()['code'], 'USER_NO_REGISTER_INSTITUTION')
|
||||
|
||||
def test_login_wrong_password(self):
|
||||
"""N7: 错误密码 → 400 AUTH_BAD_CREDENTIALS"""
|
||||
phone = '13800001004'
|
||||
create_test_user(phone=phone, password='RealPass1')
|
||||
create_test_user(phone=phone, password='RealPass1', role_type='doctor')
|
||||
resp = self.client.post(USER_LOGIN_URL, {
|
||||
'phone': phone, 'password': 'WrongPass1',
|
||||
'account': phone, 'password': 'WrongPass1', 'role': 'doctor',
|
||||
})
|
||||
self.assertIn(resp.status_code, (400, 401))
|
||||
self.assertEqual(resp.json()['code'], 'AUTH_BAD_CREDENTIALS')
|
||||
@@ -105,17 +205,17 @@ class UserNegativeTest(CacheTestCase):
|
||||
def test_login_account_lock_423(self):
|
||||
"""N8: 连续 5 次错误后第 6 次 → 423 AUTH_ACCOUNT_LOCKED"""
|
||||
phone = '13800001005'
|
||||
create_test_user(phone=phone, password='RealPass1')
|
||||
create_test_user(phone=phone, password='RealPass1', role_type='doctor')
|
||||
|
||||
# 连续 5 次错误密码
|
||||
for _ in range(5):
|
||||
self.client.post(USER_LOGIN_URL, {
|
||||
'phone': phone, 'password': 'Wrong!!!!',
|
||||
'account': phone, 'password': 'Wrong!!!!', 'role': 'doctor',
|
||||
})
|
||||
|
||||
# 第 6 次
|
||||
resp = self.client.post(USER_LOGIN_URL, {
|
||||
'phone': phone, 'password': 'Wrong!!!!',
|
||||
'account': phone, 'password': 'Wrong!!!!', 'role': 'doctor',
|
||||
})
|
||||
self.assertEqual(resp.status_code, 423, resp.content)
|
||||
self.assertEqual(resp.json()['code'], 'AUTH_ACCOUNT_LOCKED')
|
||||
|
||||
Reference in New Issue
Block a user