From f6f20084983e4bc685b078712f5fa23d2b374090 Mon Sep 17 00:00:00 2001 From: Pine Date: Wed, 26 Aug 2026 13:15:06 +0800 Subject: [PATCH] =?UTF-8?q?refactor(auth):=20=E8=B4=A6=E5=8F=B7=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E5=BD=BB=E5=BA=95=E6=94=B6=E6=95=9B=E4=B8=BA=E5=9B=9B?= =?UTF-8?q?=E7=A7=8D=20+=20=E5=90=84=E7=AB=AF=E5=8F=A3=E5=AE=88=E5=8D=AB?= =?UTF-8?q?=E6=94=B9=20service(=E5=8E=BB=E9=99=A4=E5=86=97=E4=BD=99?= =?UTF-8?q?=E8=A7=92=E8=89=B2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 迁移守卫: provider/enterprise/government/investor/developer 一律 require_roles("service") - token/profile.role 归一为四种(operator/carrier/opc_member/service); require_roles 与之一致 - 账号类型集中 app/domain/account_types.py; 子角色停用 --- app/api/routers/auth.py | 17 ++++------------- app/api/routers/rbac_developer.py | 10 +++++----- app/api/routers/rbac_ecosystem.py | 16 ++++++++-------- app/api/routers/rbac_investor.py | 24 ++++++++++++------------ app/api/routers/rbac_org.py | 14 ++++++-------- app/api/routers/rbac_portals.py | 12 ++++++------ 6 files changed, 41 insertions(+), 52 deletions(-) diff --git a/app/api/routers/auth.py b/app/api/routers/auth.py index 22c9d47..a5a789c 100644 --- a/app/api/routers/auth.py +++ b/app/api/routers/auth.py @@ -108,16 +108,7 @@ def _is_phone(account: str) -> bool: return bool(_PHONE_RE.match(account.strip())) # 账户管理页可编辑的资料字段(username 作为登录名走 update_credentials,单独处理) -_PROFILE_FIELDS = ( - "nickname", - "account", - "room", - "avatar", - "company_avatar", - "email", - "gender", - "birthday", -) +_PROFILE_FIELDS = ("nickname", "account", "room", "avatar", "company_avatar", "email", "gender", "birthday") def _identity_summaries(identities: list[dict]) -> list[IdentityInfo]: @@ -157,7 +148,7 @@ async def _issue_token( scope_level = await db.regions.level(region_id) token_user = dict(user) - token_user.update(account_type=atype, role=role, sub_role=None, org_id=org_id, region_id=region_id) + token_user.update(account_type=atype, role=atype, sub_role=None, org_id=org_id, region_id=region_id) await db.users.mark_login(user["id"]) # 记录最近登录时间(每次签发令牌=一次活动) return await db.tokens.create( token_user, @@ -199,9 +190,9 @@ async def _profile_for( profile["affiliation"] = user.get("affiliation", "independent") profile["park_id"] = user.get("park_id", "") profile["park_name"] = user.get("park_name", "") - profile["account_type"] = atype # 四种账号类型(operator/carrier/opc/service) + profile["account_type"] = atype # 四种账号类型(operator/carrier/opc/"service") profile["account_type_label"] = account_type_label(atype) - profile["role"] = role # 端口角色(兼容守卫) + profile["role"] = atype # 账号类型(四种) profile["sub_role"] = None # 子角色已停用 profile["org_id"] = org_id profile["region_id"] = region_id diff --git a/app/api/routers/rbac_developer.py b/app/api/routers/rbac_developer.py index a85457f..29d74d5 100644 --- a/app/api/routers/rbac_developer.py +++ b/app/api/routers/rbac_developer.py @@ -19,27 +19,27 @@ async def _page(port: str, page: str): @router.get("/dashboard", summary="开发者工作台") -async def dev_dashboard(db: Database = Depends(get_db), _u: dict = Depends(require_roles("developer"))): +async def dev_dashboard(db: Database = Depends(get_db), _u: dict = Depends(require_roles("service"))): return await db.portal_pages.get("developer", "dashboard") or {"stats": []} @router.get("/apps", summary="我的应用") -async def dev_apps(db: Database = Depends(get_db), _u: dict = Depends(require_roles("developer"))): +async def dev_apps(db: Database = Depends(get_db), _u: dict = Depends(require_roles("service"))): return await db.portal_pages.get("developer", "apps") or {"items": []} @router.get("/plugins", summary="我的插件") -async def dev_plugins(db: Database = Depends(get_db), _u: dict = Depends(require_roles("developer"))): +async def dev_plugins(db: Database = Depends(get_db), _u: dict = Depends(require_roles("service"))): return await db.portal_pages.get("developer", "plugins") or {"items": []} @router.get("/skills", summary="技能市场") -async def dev_skills(db: Database = Depends(get_db), _u: dict = Depends(require_roles("developer"))): +async def dev_skills(db: Database = Depends(get_db), _u: dict = Depends(require_roles("service"))): return await db.portal_pages.get("developer", "skills") or {"items": []} @router.get("/api-keys", summary="API 凭证") -async def dev_api_keys(db: Database = Depends(get_db), _u: dict = Depends(require_roles("developer"))): +async def dev_api_keys(db: Database = Depends(get_db), _u: dict = Depends(require_roles("service"))): return {"items": [ {"id": "key_001", "name": "生产环境", "prefix": "pa_live_****abcd", "created_at": "2026-07-01"}, {"id": "key_002", "name": "测试环境", "prefix": "pa_test_****wxyz", "created_at": "2026-07-05"}, diff --git a/app/api/routers/rbac_ecosystem.py b/app/api/routers/rbac_ecosystem.py index fb9713f..cab49e7 100644 --- a/app/api/routers/rbac_ecosystem.py +++ b/app/api/routers/rbac_ecosystem.py @@ -13,7 +13,7 @@ from ...infrastructure.repositories import Database router = APIRouter(tags=["ecosystem"]) -_ANY = ("opc_member", "carrier", "enterprise", "provider", "government", "operator", "investor") +_ANY = ("opc_member", "carrier", "service", "operator") # ── 通知中心 ────────────────────────────────────────────────────────────── @@ -51,7 +51,7 @@ async def rate_task( req: RatingRequest, request: Request, db: Database = Depends(get_db), - actor: dict = Depends(require_roles("enterprise", "opc_member")), + actor: dict = Depends(require_roles("service", "opc_member")), ): if not req.to_id: raise HTTPException(status_code=400, detail="缺少被评对象") @@ -66,7 +66,7 @@ async def rate_task( async def get_contract( task_id: str, db: Database = Depends(get_db), - _u: dict = Depends(require_roles("enterprise", "opc_member")), + _u: dict = Depends(require_roles("service", "opc_member")), ): contract = await db.contracts.get_for_task(task_id) if contract is None: @@ -80,7 +80,7 @@ async def sign_contract( req: SignRequest, request: Request, db: Database = Depends(get_db), - actor: dict = Depends(require_roles("enterprise", "opc_member")), + actor: dict = Depends(require_roles("service", "opc_member")), ): from ...services.settlement_service import SettlementService @@ -96,7 +96,7 @@ async def release_escrow( task_id: str, request: Request, db: Database = Depends(get_db), - actor: dict = Depends(require_roles("enterprise")), + actor: dict = Depends(require_roles("service")), ): from ...services.settlement_service import SettlementService @@ -122,7 +122,7 @@ async def create_dispute( req: DisputeRequest, request: Request, db: Database = Depends(get_db), - actor: dict = Depends(require_roles("enterprise", "opc_member")), + actor: dict = Depends(require_roles("service", "opc_member")), ): from ...services.settlement_service import SettlementService @@ -151,7 +151,7 @@ async def resolve_dispute( @router.get("/investor/matches", summary="投资撮合(按偏好推荐)") async def investor_matches( db: Database = Depends(get_db), - user: dict = Depends(require_roles("investor")), + user: dict = Depends(require_roles("service")), ): from ...services.settlement_service import SettlementService @@ -164,7 +164,7 @@ async def join_roadshow( roadshow_id: str, request: Request, db: Database = Depends(get_db), - actor: dict = Depends(require_roles("investor", "government", "operator", "carrier", "enterprise")), + actor: dict = Depends(require_roles("service", "operator", "carrier")), ): rs = await db.roadshows.get(roadshow_id) if rs is None: diff --git a/app/api/routers/rbac_investor.py b/app/api/routers/rbac_investor.py index bf9857a..76e015d 100644 --- a/app/api/routers/rbac_investor.py +++ b/app/api/routers/rbac_investor.py @@ -19,7 +19,7 @@ from ...infrastructure.repositories import Database router = APIRouter(prefix="/investor", tags=["investor"]) # 可发布投融资活动的端口角色(审核规则见 _need_review) -_ROADSHOW_ROLES = ("investor", "government", "operator", "carrier", "enterprise") +_ROADSHOW_ROLES = ("service", "operator", "carrier") def _need_review(user: dict, req: RoadshowCreate, db: Database) -> bool: @@ -27,7 +27,7 @@ def _need_review(user: dict, req: RoadshowCreate, db: Database) -> bool: role = user.get("role") if role == "operator": return False - if role == "government": + if role == "service": scope = user.get("scope_region_ids", []) if req.scope_type == "region" and req.region_id and req.region_id in scope: return False # 自身权限范围内,免审 @@ -43,7 +43,7 @@ def _pub_status(need_review: bool) -> str: @router.get("/dashboard", summary="投资人工作台") async def investor_dashboard( db: Database = Depends(get_db), - user: dict = Depends(require_roles("investor")), + user: dict = Depends(require_roles("service")), ): pref = await db.investor_prefs.get(user["id"]) or {} portfolio = await db.portal_pages.get("investor", "portfolio") or {} @@ -59,7 +59,7 @@ async def investor_dashboard( @router.get("/preferences", summary="投资方向") async def get_preferences( db: Database = Depends(get_db), - user: dict = Depends(require_roles("investor")), + user: dict = Depends(require_roles("service")), ): return await db.investor_prefs.get(user["id"]) or {} @@ -69,7 +69,7 @@ async def set_preferences( req: PreferenceRequest, request: Request, db: Database = Depends(get_db), - actor: dict = Depends(require_roles("investor")), + actor: dict = Depends(require_roles("service")), ): pref = await db.investor_prefs.upsert(actor["id"], req.model_dump(exclude_none=True)) await write_audit(db, action="preference.update", resource="investor", resource_id=actor["id"], @@ -80,7 +80,7 @@ async def set_preferences( @router.get("/projects", summary="项目库") async def list_projects( db: Database = Depends(get_db), - _u: dict = Depends(require_roles("investor")), + _u: dict = Depends(require_roles("service")), ): return await db.portal_pages.get("investor", "projects") or {"items": []} @@ -88,7 +88,7 @@ async def list_projects( @router.get("/trainings", summary="投融资培训") async def list_trainings( db: Database = Depends(get_db), - _u: dict = Depends(require_roles("investor")), + _u: dict = Depends(require_roles("service")), ): return await db.portal_pages.get("investor", "trainings") or {"items": []} @@ -98,7 +98,7 @@ async def enroll_training( training_id: str, request: Request, db: Database = Depends(get_db), - actor: dict = Depends(require_roles("investor")), + actor: dict = Depends(require_roles("service")), ): data = await db.portal_pages.get("investor", "trainings") or {"items": []} item = next((it for it in data.get("items", []) if it.get("title") == training_id), None) @@ -112,7 +112,7 @@ async def enroll_training( @router.get("/my-trainings", summary="我的培训") async def my_trainings( db: Database = Depends(get_db), - user: dict = Depends(require_roles("investor")), + user: dict = Depends(require_roles("service")), ): return {"items": await db.training_enrolls.list_for(user["id"])} @@ -120,7 +120,7 @@ async def my_trainings( @router.get("/portfolio", summary="投资组合") async def portfolio( db: Database = Depends(get_db), - _u: dict = Depends(require_roles("investor")), + _u: dict = Depends(require_roles("service")), ): return await db.portal_pages.get("investor", "portfolio") or {"items": []} @@ -131,7 +131,7 @@ async def create_intent( req: IntentRequest, request: Request, db: Database = Depends(get_db), - actor: dict = Depends(require_roles("investor")), + actor: dict = Depends(require_roles("service")), ): intent = await db.intents.create( actor["id"], req.project_id or project_id, req.project_name, req.message, @@ -144,7 +144,7 @@ async def create_intent( @router.get("/intents", summary="我的投资意向") async def list_intents( db: Database = Depends(get_db), - user: dict = Depends(require_roles("investor")), + user: dict = Depends(require_roles("service")), ): return {"items": await db.intents.list_for(user["id"])} diff --git a/app/api/routers/rbac_org.py b/app/api/routers/rbac_org.py index c8f8165..6aa223a 100644 --- a/app/api/routers/rbac_org.py +++ b/app/api/routers/rbac_org.py @@ -16,9 +16,7 @@ router = APIRouter(tags=["org"]) @router.get("/org/me", summary="当前组织信息") async def org_me( db: Database = Depends(get_db), - user: dict = Depends(require_roles( - "opc_member", "carrier", "enterprise", "provider", "government", "operator", - )), + user: dict = Depends(require_roles("opc_member", "carrier", "service", "operator")), ): org = await db.orgs.get(user["org_id"]) if user.get("org_id") else None region = await db.regions.get(user["region_id"]) if user.get("region_id") else None @@ -34,7 +32,7 @@ async def org_me( @router.get("/enterprise/profile", summary="企业资料") async def enterprise_profile( db: Database = Depends(get_db), - user: dict = Depends(require_roles("enterprise")), + user: dict = Depends(require_roles("service")), ): org = await db.orgs.get(user["org_id"]) if user.get("org_id") else None if org is None: @@ -55,7 +53,7 @@ async def carrier_enterprises( @router.get("/provider/orders", summary="服务商订单(骨架)") async def provider_orders( - user: dict = Depends(require_roles("provider")), + user: dict = Depends(require_roles("service")), ): """占位:服务商仅返回本 org 的订单(业务逻辑后续阶段补齐)。""" return {"org_id": user.get("org_id"), "orders": []} @@ -67,7 +65,7 @@ async def provider_orders( async def org_members( org_id: str, db: Database = Depends(get_db), - user: dict = Depends(require_roles("enterprise", "carrier", "provider", "investor", "operator")), + user: dict = Depends(require_roles("service", "carrier", "operator")), ): # 机构管理员本人 或 平台运营 可查看 if user.get("role") not in ("operator",) and not await db.org_members.is_admin(org_id, user["id"]): @@ -80,7 +78,7 @@ async def org_add_member( org_id: str, req: OrgMemberAdd, db: Database = Depends(get_db), - user: dict = Depends(require_roles("enterprise", "carrier", "provider", "investor", "operator")), + user: dict = Depends(require_roles("service", "carrier", "operator")), ): if user.get("role") not in ("operator",) and not await db.org_members.is_admin(org_id, user["id"]): raise HTTPException(status_code=403, detail="Forbidden: not org admin") @@ -98,7 +96,7 @@ async def org_add_member( @router.get("/me/orgs", summary="我加入的机构") async def my_orgs( db: Database = Depends(get_db), - user: dict = Depends(require_roles("enterprise", "carrier", "provider", "investor")), + user: dict = Depends(require_roles("service", "carrier")), ): """返回当前账号挂靠的所有机构及成员角色(支持一账号多机构)。""" from ...services.org_service import OrgService diff --git a/app/api/routers/rbac_portals.py b/app/api/routers/rbac_portals.py index 6d0ca2e..a0c2cb7 100644 --- a/app/api/routers/rbac_portals.py +++ b/app/api/routers/rbac_portals.py @@ -79,7 +79,7 @@ router.get("/government/policies", summary="政务·政策管理")(_page("govern @router.get("/enterprise/tasks", summary="企业·我的任务列表") async def enterprise_tasks( db: Database = Depends(get_db), - _u: dict = Depends(require_roles("enterprise")), + _u: dict = Depends(require_roles("service")), ): return {"items": await db.tasks.list(status="published")} @@ -89,7 +89,7 @@ async def enterprise_create_task( req: EnterpriseTaskCreate, request: Request, db: Database = Depends(get_db), - actor: dict = Depends(require_roles("enterprise")), + actor: dict = Depends(require_roles("service")), ): task = await db.tasks.create({**req.model_dump(exclude_none=True), "status": "pending"}) await write_audit(db, action="task.publish", resource="task", resource_id=task["id"], @@ -102,7 +102,7 @@ async def enterprise_submit_task( task_id: str, request: Request, db: Database = Depends(get_db), - actor: dict = Depends(require_roles("enterprise")), + actor: dict = Depends(require_roles("service")), ): task = await db.tasks.set_status(task_id, "published") if task is None: @@ -116,7 +116,7 @@ async def enterprise_submit_task( async def enterprise_list_bids( task_id: str, db: Database = Depends(get_db), - _u: dict = Depends(require_roles("enterprise")), + _u: dict = Depends(require_roles("service")), ): return {"items": await db.bids.list_for_task(task_id)} @@ -126,7 +126,7 @@ async def enterprise_win_bid( task_id: str, bid_id: str, request: Request, db: Database = Depends(get_db), - actor: dict = Depends(require_roles("enterprise")), + actor: dict = Depends(require_roles("service")), ): bid = await db.bids.set_status(bid_id, "win") if bid is None: @@ -143,7 +143,7 @@ async def enterprise_review_task( req: TaskReviewRequest, request: Request, db: Database = Depends(get_db), - actor: dict = Depends(require_roles("enterprise")), + actor: dict = Depends(require_roles("service")), ): task = await db.tasks.get(task_id) if task is None: