托管登录握手

登录只有一条路:产品站把用户跳到 login. 托管门户,回跳拿一次性 login_code,服务端换 access_token。

登录唯一入口login. 托管门户——邮箱与微信都在门户内完成,产品站零配微信。原始 token 不出现在浏览器 URL 里,改用一次性 login_code 由服务端换票。

用户浏览器产品站服务端login. 托管门户① 302 GET /login?return_to=…&site=…② 展示托管登录页(邮箱 / 微信)③ 提交登录(微信内 /login/mp?silent=1 静默)④ 302 → return_to?login_code=…⑤ GET /callback?login_code=…⑥ POST /api/v1/auth/exchange { code }⑦ { access_token, expires_in, user }⑧ Set-Cookie(HttpOnly)+ 302 回站内

① 跳转托管门户

把用户浏览器 302 到门户,带上回跳地址与站点 slug:

text
https://login.rekitdev.com/login?return_to=https://你的站/api/auth/callback?returnTo=/&site=your-slug
Query必填说明
return_to登录后回跳的产品站 URL,host 须在站点白名单内;可自带 query
site后台站点 slug
langzh / en
PC 扫码用 /login;微信内 H5 用 /login/mp(见「微信内静默登录」)。两者回跳形态一致。

② 回跳带回 login_code

登录成功后门户 302 回你的 return_to,仅追加 login_code

text
302 → https://你的站/api/auth/callback?returnTo=/&login_code=xxxxxxxx

③ 服务端换票

POST/api/v1/auth/exchange
用一次性 login_code 换 access_token + user
请求
POST https://login.rekitdev.com/api/v1/auth/exchange
Content-Type: application/json

{ "code": "回跳带回的 login_code" }
响应
{
  "access_token": "<JWT>",
  "expires_in": 86400,
  "user": { "id": 123, "nickname": "...", "email": "...", "unionid": "oUnion..." }
}
务必在服务端换票
login_code 一次性、90s 有效。产品站服务端换到 access_token 后写自己的 HttpOnly Cookie,再 302 回站内 returnTo。原始 token 不要落到浏览器 URL / localStorage。