外部项目接入 Auth 指南

本文说明如何让外部项目复用 https://auth.ephron.ren 的登录体系。

1. 接入目标

  • 外部项目未登录时,跳转到 Auth 登录页。
  • 用户登录后,自动回到外部项目原页面。
  • 外部项目可主动校验当前登录态和角色权限。

2. 登录跳转协议

2.1 未登录时跳转到 Auth

推荐 URL:

https://auth.ephron.ren/?redirect=<URL-ENCODE(当前页面完整URL)>

也可以直接跳 /login

https://auth.ephron.ren/login?redirect=<URL-ENCODE(当前页面完整URL)>

Auth 当前支持以下回跳参数(等价):

  • redirect(推荐)
  • return_url
  • next

2.2 登录成功后回跳

POST /api/login 登录成功后会 303 跳转到回跳地址。

若回跳地址非法,会降级到:

/login-success

3. 回跳地址校验规则(重要)

Auth 为防止 Open Redirect,仅允许以下回跳地址:

  • 相对路径(如 /admin
  • *.ephron.ren 域名
  • 开发环境下 localhost / 127.0.0.1

这意味着:

  • 外部项目若不在 *.ephron.ren 下,登录后不会直接回跳到该域名。
  • 会被拦截并落到 /login-success

4. 外部项目如何判断已登录

外部项目可使用两种方式。

  • 读取 ephron_auth Cookie。
  • 用同一 AUTH_SECRET_KEY 进行签名校验。

4.2 调 Auth 校验接口(推荐给网关/反向代理/独立服务)

GET /api/auth/verify?min_role=user
Host: auth.ephron.ren
Cookie: ephron_auth=<token>

返回语义:

  • 200:已登录且权限满足。
  • 401:未登录或 token 无效。
  • 403:已登录但权限不足。
  • 400min_role 参数非法。

当前支持 min_role

  • user
  • admin
  • owner

5. 最小接入示例(FastAPI)

from urllib.parse import quote

import httpx
from fastapi import Request
from fastapi.responses import RedirectResponse

AUTH_LOGIN_BASE = "https://auth.ephron.ren/"
AUTH_VERIFY_URL = "https://auth.ephron.ren/api/auth/verify?min_role=user"


async def require_login(request: Request):
    token = request.cookies.get("ephron_auth")
    if not token:
        current_url = str(request.url)
        return RedirectResponse(
            url=f"{AUTH_LOGIN_BASE}?redirect={quote(current_url, safe='')}",
            status_code=302,
        )

    async with httpx.AsyncClient(timeout=3.0) as client:
        resp = await client.get(
            AUTH_VERIFY_URL,
            headers={"Cookie": f"ephron_auth={token}"},
        )

    if resp.status_code != 200:
        current_url = str(request.url)
        return RedirectResponse(
            url=f"{AUTH_LOGIN_BASE}?redirect={quote(current_url, safe='')}",
            status_code=302,
        )

    return None

6. 常见问题

6.1 登录后没有自动跳回原页面

请检查:

  • 是否传了回跳参数(推荐 redirect)。
  • 回跳地址是否在允许范围(见第 3 节)。
  • 是否在中间跳转链路丢失了参数。

6.2 为什么登录后回到了 /login-success

通常是回跳地址未通过校验(最常见是目标域名不在 *.ephron.ren)。

6.3 不同顶级域能直接共享登录态吗

不能直接共享 Cookie Domain=.ephron.ren。不同顶级域需要单独设计 OAuth 或票据交换流程。

7. 推荐接入清单

  • 所有需要登录的页面都走统一 require_login 中间件。
  • 始终传 redirect 且值为当前完整 URL。
  • 服务端做权限校验,不仅依赖前端按钮显隐。
  • 401403 做区分处理(未登录 vs 权限不足)。