dingdanquanliucheng/backend/app/services/auth_service.py

118 lines
5.3 KiB
Python

from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session
from backend.app.core.error_codes import ErrorCode
from backend.app.core.exceptions import AppException
from backend.app.repositories.system_repository import SystemRepository
from backend.app.services.demo_store import demo_store
class AuthService:
DEFAULT_ROLE_MENUS = {
"salesman": [{"menu_name": "我的订单", "menu_path": "/orders"}],
"manager": [{"menu_name": "审批中心", "menu_path": "/pages/approve-list"}],
"driver": [{"menu_name": "我的任务", "menu_path": "/pages/task-list"}],
"admin": [{"menu_name": "后台首页", "menu_path": "/dashboard"}],
}
DEFAULT_ROLE_PERMISSIONS = {
"salesman": ["order:create", "order:list", "order:submit", "customer:list"],
"manager": ["order:list", "order:approve", "order:cancel-approve", "logistics:task:create"],
"driver": ["driver:task:list", "driver:task:accept", "driver:task:pickup", "driver:task:deliver"],
"admin": ["system:user:list", "system:role:list", "system:menu:list", "order:list"],
}
def __init__(self) -> None:
self.repository = SystemRepository()
def login(self, username: str, password: str, role_type: str, session: Session | None = None) -> dict | None:
if session is not None:
try:
user = self.repository.get_user_by_username(session, username)
if user is None or user.password_hash != password:
raise AppException(
code=ErrorCode.UNAUTHORIZED,
message="账号不存在或密码错误",
status_code=401,
)
role = self.repository.get_role(session, user.role_id)
if role is None:
raise AppException(code=ErrorCode.NOT_FOUND, message="角色不存在", status_code=404)
if user.status != 1:
raise AppException(code=ErrorCode.FORBIDDEN, message="账号已停用", status_code=403)
if role.status != 1 or role.role_code != role_type:
raise AppException(code=ErrorCode.FORBIDDEN, message="登录角色与账号不匹配", status_code=403)
return self._build_profile(session, user, role, include_token=True)
except AppException:
raise
except SQLAlchemyError:
pass
return demo_store.login(username, role_type)
def get_me(self, token: str, session: Session | None = None) -> dict | None:
if session is not None and token.startswith("db-user-"):
try:
user_id = int(token.split("-")[2])
user = self.repository.get_user(session, user_id)
if user is None or user.status != 1:
return None
role = self.repository.get_role(session, user.role_id)
if role is None or role.status != 1:
return None
return self._build_profile(session, user, role, include_token=False)
except (SQLAlchemyError, ValueError, IndexError):
pass
return demo_store.get_me(token)
def _build_profile(self, session: Session, user, role, include_token: bool) -> dict:
menus = self._load_role_menus(session, role.role_code)
permissions = self._load_role_permissions(session, role.role_code)
return {
"user_id": user.id,
"username": user.username,
"real_name": user.real_name,
"mobile": user.mobile,
"role_id": role.id,
"role_name": role.role_name,
"role_code": role.role_code,
"token": f"db-user-{user.id}-{role.role_code}" if include_token else None,
"menus": menus,
"permissions": permissions,
}
def _load_role_menus(self, session: Session, role_code: str) -> list[dict]:
menus = self.repository.list_menus(session, {"status": 1})
if not menus:
return self.DEFAULT_ROLE_MENUS.get(role_code, [])
if role_code == "admin":
return [{"menu_name": menu.menu_name, "menu_path": menu.menu_path} for menu in menus]
allowed_paths = {item["menu_path"] for item in self.DEFAULT_ROLE_MENUS.get(role_code, [])}
filtered = [
{"menu_name": menu.menu_name, "menu_path": menu.menu_path}
for menu in menus
if menu.menu_path in allowed_paths
]
return filtered or self.DEFAULT_ROLE_MENUS.get(role_code, [])
def _load_role_permissions(self, session: Session, role_code: str) -> list[str]:
menus = self.repository.list_menus(session, {"status": 1})
if not menus:
return self.DEFAULT_ROLE_PERMISSIONS.get(role_code, [])
if role_code == "admin":
permissions = [menu.permission_code for menu in menus if menu.permission_code]
return permissions or self.DEFAULT_ROLE_PERMISSIONS.get(role_code, [])
allowed = set(self.DEFAULT_ROLE_PERMISSIONS.get(role_code, []))
permissions = [menu.permission_code for menu in menus if menu.permission_code in allowed]
return permissions or self.DEFAULT_ROLE_PERMISSIONS.get(role_code, [])
auth_service = AuthService()