99520c69d7
1.新增后端测试 2.增加了后端的加密 3.增加了i18n(国际化)
72 lines
2.7 KiB
Python
72 lines
2.7 KiB
Python
# Copyright 2026 zhaoxi826
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
from typing import Annotated
|
|
from fastapi import Depends, HTTPException, Request
|
|
from kilostar.utils.access import Accessor, TokenData
|
|
from kilostar.core.postgres_database.model import UserAuthority
|
|
from kilostar.utils.ray_hook import ray_actor_hook
|
|
from kilostar.utils.i18n import t
|
|
|
|
|
|
def _user_not_found_detail(request: Request | None = None) -> str:
|
|
loc = request.headers.get("accept-language") if request else None
|
|
return t("user_not_found", accept_language=loc)
|
|
|
|
|
|
async def get_authority(user_id: str) -> UserAuthority:
|
|
"""通过 PostgresDatabase Actor 查出指定用户的 ``UserAuthority``;用户不存在时抛 401。"""
|
|
from kilostar.utils.error import UserNotExistError
|
|
|
|
postgres_database = ray_actor_hook("postgres_database").postgres_database
|
|
try:
|
|
user_authority = await postgres_database.get_user_authority.remote(
|
|
user_id=user_id
|
|
)
|
|
return user_authority
|
|
except UserNotExistError:
|
|
raise HTTPException(status_code=401, detail=t("user_not_found"))
|
|
except Exception as e:
|
|
# Check if it's a RayTaskError wrapping UserNotExistError
|
|
if "UserNotExistError" in str(e):
|
|
raise HTTPException(
|
|
status_code=401, detail=t("user_not_found")
|
|
)
|
|
raise
|
|
|
|
|
|
class RoleChecker:
|
|
"""FastAPI 依赖:在路由级别按 ``UserAuthority`` 做最低权限校验。
|
|
|
|
例:``Depends(RoleChecker(allowed_roles=UserAuthority.ADMINISTRATOR))``。
|
|
"""
|
|
|
|
def __init__(self, **kwargs):
|
|
self.allowed_roles = kwargs.get(
|
|
"allowed_roles",
|
|
)
|
|
|
|
async def __call__(
|
|
self, token_data: Annotated[TokenData, Depends(Accessor.get_current_user)]
|
|
):
|
|
"""对当前请求执行权限比较,权限不足抛 403,否则把 ``TokenData`` 透传给路由。"""
|
|
user_authority = await get_authority(token_data.user_id)
|
|
if user_authority < self.allowed_roles:
|
|
raise HTTPException(
|
|
status_code=403,
|
|
detail={
|
|
"message": f"User {token_data.user_id} does not have allowed roles"
|
|
},
|
|
)
|
|
return token_data
|