在法国用 FranceConnect 对接自建服务,回调地址别写 localhost
上周帮朋友的小协会把会员登录接到 FranceConnect 的测试环境(integration),本地是 Docker Compose 起的一个 Django 服务,Postgres 15,数据量很小,会员记录不到 800 条,但认证流程的坑一点没少。现象很直接:本地用 http://localhost:8000/callback 怎么都过不去,浏览器跳回 FranceConnect 后停在错误页,服务端日志里只有一条 400,没有更多信息。
我的做法是把回调拆成两段。FranceConnect 这边登记的回调必须是可公网访问的 HTTPS 地址,本地调试就用一个反向隧道把 8000 端口暴露出去,然后把这个域名写进控制台的 redirect_uri。服务端配置里保留一个白名单,本地和生产各一套:
# settings.py 片段
FRANCECONNECT = {
"client_id": os.environ["FC_CLIENT_ID"],
"client_secret": os.environ["FC_CLIENT_SECRET"],
"redirect_uri": os.environ["FC_REDIRECT_URI"], # 必须与登记值逐字符一致
"scope": "openid given_name family_name email",
"authorization_endpoint": "https://fcp.integ01.dev-franceconnect.fr/api/v1/authorize",
"token_endpoint": "https://fcp.integ01.dev-franceconnect.fr/api/v1/token",
}
回调视图里先校验 state,再换 token,最后只用 sub 做用户绑定,不去存储 FranceConnect 返回的其他身份字段:
state = request.GET.get("state")
if state != request.session.pop("fc_state", None):
return HttpResponseBadRequest("state mismatch")
code = request.GET.get("code")
token = requests.post(cfg["token_endpoint"], data={
"grant_type": "authorization_code",
"code": code,
"redirect_uri": cfg["redirect_uri"],
"client_id": cfg["client_id"],
"client_secret": cfg["client_secret"],
}, timeout=10).json()
为什么这样:FranceConnect 对 redirect_uri 做的是精确匹配,不是前缀匹配,localhost、末尾多一个斜杠、http 和 https 混用都会被拒;而 state 放 session 里是为了防止回调被重放,代价是调试时如果重启容器,session 会失效,需要重新走一遍授权。另外 token 请求里的 redirect_uri 必须和授权时完全一样,这一点最容易在复制粘贴时出错。
会失效的地方:隧道域名每次重启都会变,测试环境里要记得同步改控制台登记值;协会用的是 integration 环境,数据和正式环境不互通,别拿真实会员去试;如果服务前面加了 Nginx,记得把 X-Forwarded-Proto 传进去,否则 Django 生成的绝对 URL 会退成 http,回调又对不上。我自己就卡在这个 header 上半小时,日志里看不出原因。
你们在法国接这类公共身份服务时,是把回调固定成一个测试子域名,还是每次开隧道都改登记?
0 条评论
还没有评论,写下第一条。