# 极光一键登录 — 服务端核验 + RSA 解密手机号(jiguang) > 文件:`app/integrations/jiguang.py` | 关联接口:[auth-jverify-login](../api/auth-jverify-login.md) | [← 集成索引](./README.md) ## 作用 极光一键登录的服务端环节:拿客户端的 `loginToken` 调极光 REST 验真,取回 RSA 加密的手机号并解密成明文。 ## 链路 ``` Android SDK loginAuth → loginToken → 本服务 POST 极光 /v1/web/loginTokenVerify (Basic Auth = AppKey:MasterSecret) → 极光返回 RSA 公钥加密的手机号 (base64) → 用配套 RSA 私钥解密 → 返回明文手机号 ``` ## 函数 / 异常 - `verify_and_get_phone(login_token)` —— 对外入口,验证 + 解密一把梭。 - 失败统一抛 `JiguangError`,api 层 catch 后翻成 4xx/5xx(验证失败/解密失败 → `502`)。 - RSA 私钥**懒加载并缓存**(`_private_key_cache`):文件缺失抛 `JiguangError`(让单请求失败 + 日志,而不是 import 时炸进程)。 ## RSA 解密策略(关键) 极光文档没明说 padding。实测 PKCS1v15 套在 OAEP 密文上会"假成功"返回垃圾(`UnicodeDecodeError 0x8e`)。因此按 **OAEP-SHA1 → OAEP-SHA256 → PKCS1v15** 顺序尝试,谁能解出 **11 位纯数字手机号**就用谁;base64 先按 4 字节对齐补 `=`(各运营商可能返回不带 `=` 的 base64)。 ## 配置 | 配置项 | 说明 | |---|---| | `JG_APP_KEY` / `JG_MASTER_SECRET` | 极光 AppKey / MasterSecret(拼 Basic Auth) | | `JG_PRIVATE_KEY_PATH` | RSA 私钥 .pem 路径 | | `JG_VERIFY_ENDPOINT` | 极光验证接口 URL(`/v1/web/loginTokenVerify`) | | `JG_REQUEST_TIMEOUT_SEC` | 请求超时 | ## 踩坑 - **私钥必须与极光控制台为该 appkey 登记的公钥配对**,否则三种 padding 全失败、报 `all RSA paddings failed; last error: Decryption failed`。私钥由相关开发同学生成提供。 - **换私钥后必须重启后端**——`_private_key_cache` 会缓存旧 key。 - 极光验证响应 `code != 8000` 视为失败;缺 `phone` 字段也失败。