| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- """门户跳转登录接口:验签/按需落库 + 首次设密。"""
- from __future__ import annotations
- from flask import request
- from dms.api.v1.blueprint import api_v1
- from dms.common.errors import InvalidArgumentError, LoginIpForbiddenError
- from dms.common.response import success_response
- from dms.services.audit_service import record_login_failure
- from dms.services.portal_auth_service import setup_portal_password, verify_portal_launch
- def _verify_payload() -> str:
- if not request.is_json:
- raise InvalidArgumentError("请求体必须是JSON对象")
- body = request.get_json(silent=True)
- if not isinstance(body, dict) or set(body) != {"query"}:
- raise InvalidArgumentError("请求体必须且只能包含query")
- query = body["query"]
- if not isinstance(query, str) or not query.strip():
- raise InvalidArgumentError("query不能为空")
- return query.strip()
- @api_v1.post("/auth/portal/verify")
- def portal_verify():
- """门户跳转验签:透传浏览器地址栏query串,返回跳转阶段与用户名。"""
- return success_response(verify_portal_launch(_verify_payload()))
- def _setup_payload() -> tuple[str, str, bool, str | None]:
- if not request.is_json:
- raise InvalidArgumentError("请求体必须是JSON对象")
- body = request.get_json(silent=True)
- if not isinstance(body, dict):
- raise InvalidArgumentError("请求体必须是JSON对象")
- required = {"portalTicket", "newPassword", "keepSignedIn"}
- allowed = required | {"organizationId"}
- if not required.issubset(set(body)) or set(body) - allowed:
- raise InvalidArgumentError(
- "请求体必须包含portalTicket、newPassword、keepSignedIn"
- + "(organizationId可选)"
- )
- ticket = body["portalTicket"]
- password = body["newPassword"]
- keep_signed_in = body["keepSignedIn"]
- organization_id = body.get("organizationId")
- if not isinstance(ticket, str) or not ticket.strip():
- raise InvalidArgumentError("portalTicket不能为空")
- if not isinstance(password, str) or not password:
- raise InvalidArgumentError("newPassword不能为空")
- if not isinstance(keep_signed_in, bool):
- raise InvalidArgumentError("keepSignedIn必须是布尔值")
- if organization_id is not None and (
- not isinstance(organization_id, str) or not organization_id.strip()
- ):
- raise InvalidArgumentError("organizationId必须是非空字符串")
- return (
- ticket.strip(),
- password,
- keep_signed_in,
- organization_id.strip() if organization_id is not None else None,
- )
- @api_v1.post("/auth/portal/setup-password")
- def portal_setup_password():
- """门户用户首次设置独立密码并登录(票据一次性,5分钟内有效)。"""
- ticket, password, keep_signed_in, organization_id = _setup_payload()
- try:
- payload = setup_portal_password(
- ticket, password, keep_signed_in, organization_id
- )
- except LoginIpForbiddenError:
- record_login_failure(
- user=None,
- attempted_username="(portal-setup)",
- failure_reason="IP_NOT_ALLOWED",
- )
- raise
- return success_response(payload)
|