Skip to content

Commit 24024d4

Browse files
authored
fix that the data validation global exception handler does not work (#40)
* fix that the data validation global exception handler does not work * update login api test * update the JSON login method to create the user ID of the token
1 parent 768a13f commit 24024d4

File tree

7 files changed

+66
-49
lines changed

7 files changed

+66
-49
lines changed

backend/app/api/service/user_service.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ async def login(form_data: OAuth2PasswordRequestForm):
2626
raise errors.AuthorizationError(msg='该用户已被锁定,无法登录')
2727
# 更新登陆时间
2828
await UserDao.update_user_login_time(db, form_data.username)
29+
# 获取最新用户信息
30+
user = await UserDao.get_user_by_id(db, current_user.id)
2931
# 创建token
30-
access_token = jwt.create_access_token(current_user.id)
31-
return access_token, current_user.is_superuser
32+
access_token = jwt.create_access_token(user.id)
33+
return access_token, user
3234

3335
# @staticmethod
3436
# async def login(obj: Auth):
@@ -42,9 +44,11 @@ async def login(form_data: OAuth2PasswordRequestForm):
4244
# raise errors.AuthorizationError(msg='该用户已被锁定,无法登录')
4345
# # 更新登陆时间
4446
# await UserDao.update_user_login_time(db, obj.username)
47+
# # 获取最新用户信息
48+
# user = await UserDao.get_user_by_id(db, current_user.id)
4549
# # 创建token
46-
# access_token = jwt.create_access_token(current_user.id)
47-
# return access_token, current_user.is_superuser
50+
# access_token = jwt.create_access_token(user.id)
51+
# return access_token, user
4852

4953
@staticmethod
5054
async def register(obj: CreateUser):

backend/app/api/v1/auth/user.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,18 @@
1313
router = APIRouter()
1414

1515

16-
@router.post('/login', summary='表单登录', response_model=Token, description='form 格式登录支持直接在 api 文档调试接口')
16+
@router.post('/login', summary='表单登录', description='form 格式登录,支持直接在 api 文档调试接口')
1717
async def user_login(form_data: OAuth2PasswordRequestForm = Depends()):
18-
token, is_super = await UserService.login(form_data)
19-
return Token(access_token=token, is_superuser=is_super)
18+
token, user = await UserService.login(form_data)
19+
data = Token(access_token=token, user=user)
20+
return response_base.response_200(data=data)
2021

2122

22-
# @router.post('/login', summary='用户登录', response_model=Token,
23-
# description='json 格式登录, 不支持api文档接口调试, 需使用第三方api工具, 例如: postman')
23+
# @router.post('/login', summary='用户登录', description='json 格式登录, 仅支持在第三方api工具调试接口, 例如: postman')
2424
# async def user_login(obj: Auth):
25-
# token, is_super = await UserService.login(obj)
26-
# return Token(access_token=token, is_superuser=is_super)
25+
# token, user = await UserService.login(obj)
26+
# data = Token(access_token=token, user=user)
27+
# return response_base.response_200(data=data)
2728

2829

2930
@router.post('/register', summary='用户注册')

backend/app/common/exception/exception_handler.py

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -50,42 +50,55 @@ def http_exception_handler(request: Request, exc: HTTPException):
5050
headers=exc.headers,
5151
)
5252

53+
@app.exception_handler(RequestValidationError)
54+
def validation_exception_handler(request: Request, exc: RequestValidationError):
55+
"""
56+
数据验证异常处理
57+
58+
:param request:
59+
:param exc:
60+
:return:
61+
"""
62+
message = ''
63+
data = {}
64+
for raw_error in exc.raw_errors:
65+
if isinstance(raw_error.exc, ValidationError):
66+
exc = raw_error.exc
67+
if hasattr(exc, 'model'):
68+
fields = exc.model.__dict__.get('__fields__')
69+
for field_key in fields.keys():
70+
field_title = fields.get(field_key).field_info.title
71+
data[field_key] = field_title if field_title else field_key
72+
errors_len = len(exc.errors())
73+
for error in exc.errors():
74+
field = str(error.get('loc')[-1])
75+
_msg = error.get('msg')
76+
errors_len = errors_len - 1
77+
message += (
78+
f'{data.get(field, field)} {_msg}' + ', '
79+
if errors_len > 0
80+
else f'{data.get(field, field)} {_msg}'
81+
)
82+
elif isinstance(raw_error.exc, json.JSONDecodeError):
83+
message += 'json解析失败'
84+
return JSONResponse(
85+
status_code=422,
86+
content=response_base.fail(
87+
code=422,
88+
msg='请求参数非法' if len(message) == 0 else f'请求参数非法: {message[:-1]}',
89+
data={'errors': exc.errors()} if message == '' and settings.UVICORN_RELOAD is True else None,
90+
),
91+
)
92+
5393
@app.exception_handler(Exception)
54-
def all_exception_handler(request: Request, exc):
94+
def all_exception_handler(request: Request, exc: Exception):
5595
"""
5696
全局异常处理
5797
5898
:param request:
5999
:param exc:
60100
:return:
61101
"""
62-
# 常规
63-
if isinstance(exc, RequestValidationError):
64-
message = ''
65-
data = {}
66-
for raw_error in exc.raw_errors:
67-
if isinstance(raw_error.exc, ValidationError):
68-
exc = raw_error.exc
69-
if hasattr(exc, 'model'):
70-
fields = exc.model.__dict__.get('__fields__')
71-
for field_key in fields.keys():
72-
field_title = fields.get(field_key).field_info.title
73-
data[field_key] = field_title if field_title else field_key
74-
for error in exc.errors():
75-
field = str(error.get('loc')[-1])
76-
_msg = error.get('msg')
77-
message += f'{data.get(field, field)} {_msg},'
78-
elif isinstance(raw_error.exc, json.JSONDecodeError):
79-
message += 'json解析失败'
80-
return JSONResponse(
81-
status_code=422,
82-
content=response_base.fail(
83-
msg='请求参数非法' if len(message) == 0 else f'请求参数非法:{message[:-1]}',
84-
data={'errors': exc.errors()} if message == '' and settings.UVICORN_RELOAD is True else None,
85-
),
86-
)
87-
88-
# 自定义
89102
if isinstance(exc, BaseExceptionMixin):
90103
return JSONResponse(
91104
status_code=_get_exception_code(exc.code),

backend/app/schemas/token.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
#!/usr/bin/env python3
22
# -*- coding: utf-8 -*-
3-
43
from pydantic import BaseModel
54

5+
from backend.app.schemas.user import GetUserInfo
6+
67

78
class Token(BaseModel):
8-
code: int = 200
9-
msg: str = 'Success'
109
access_token: str
1110
token_type: str = 'Bearer'
12-
is_superuser: bool | None = None
11+
user: GetUserInfo

backend/app/schemas/user.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python3
22
# -*- coding: utf-8 -*-
3-
import datetime
3+
from datetime import datetime
44

55
from pydantic import BaseModel, Field, HttpUrl
66

@@ -28,10 +28,10 @@ class GetUserInfo(UpdateUser):
2828
id: int
2929
uid: str
3030
avatar: str | None = None
31-
time_joined: datetime.datetime = None
32-
last_login: datetime.datetime | None = None
33-
is_superuser: bool
3431
is_active: bool
32+
is_superuser: bool
33+
time_joined: datetime = None
34+
last_login: datetime | None = None
3535

3636
class Config:
3737
orm_mode = True

backend/app/test/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ async def function_fixture(anyio_backend):
2525
}
2626
async with AsyncClient() as client:
2727
response = await client.post(**auth_data)
28-
token = response.json()['access_token']
28+
token = response.json()['data']['access_token']
2929
test_token = await redis_client.get('test_token')
3030
if not test_token:
3131
await redis_client.set('test_token', token, ex=86400)

backend/app/test/test_auth.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ async def test_login(self):
3131
url=f'{self.users_api_base_url}/login', data={'username': '1', 'password': '1'}
3232
)
3333
assert response.status_code == 200
34-
assert response.json()['token_type'] == 'Bearer'
34+
assert response.json()['data']['token_type'] == 'Bearer'
3535

3636
async def test_register(self):
3737
async with AsyncClient(

0 commit comments

Comments
 (0)