"""开发联调 JWT 签发 CLI(T-01 · 仅 development;生产由 IdP 签 RS256)。 用法(Git Bash / PowerShell): python scripts/dev/issue_dev_token.py --sub STAFF-30001 --roles risk_officer python scripts/dev/issue_dev_token.py --sub CUST-9527 --roles customer \\ --token-type customer --customer-id CUST-9527 签发后经 `Authorization: Bearer ` 调用,JWT 通道须带 `X-Agent-Type` (手册 §4.6)。HS256 密钥取 .env JWT_DEV_SECRET;APP_ENV != development 时 拒绝签发(防止对称密钥流出)。 """ from __future__ import annotations import argparse import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parents[2])) from app.config.settings import settings # noqa: E402 from app.service.auth_service import issue_dev_token # noqa: E402 def main() -> int: parser = argparse.ArgumentParser(description="issue a development JWT (HS256)") parser.add_argument("--sub", required=True, help="staff_id 或 customer_id(手册 §3)") parser.add_argument("--roles", required=True, help="逗号分隔角色,如 risk_officer / customer") parser.add_argument("--token-type", default="staff", choices=["customer", "staff", "service"]) parser.add_argument("--customer-id", default=None, help="token_type=customer 时必填且须等于 sub") parser.add_argument("--exp-minutes", type=int, default=60) parser.add_argument("--tenant-id", default="TENANT-001") args = parser.parse_args() if settings.app_env != "development": print("refused: issue_dev_token only runs with APP_ENV=development", file=sys.stderr) return 1 roles = [r.strip() for r in args.roles.split(",") if r.strip()] if args.token_type == "customer" and args.customer_id != args.sub: print("refused: customer token requires --customer-id equal to --sub (手册 §4.2)", file=sys.stderr) return 1 token = issue_dev_token( sub=args.sub, roles=roles, token_type=args.token_type, exp_minutes=args.exp_minutes, tenant_id=args.tenant_id, customer_id=args.customer_id, ) print(token) return 0 if __name__ == "__main__": raise SystemExit(main())