You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI集成Apple登录时state不匹配引发CSRF错误排查求助

FastAPI集成Apple登录时state不匹配引发CSRF错误排查求助

大家好,我现在在FastAPI中集成Apple登录时遇到了棘手的CSRF状态不匹配问题,折腾了好一阵没找到根因,想请社区的朋友们帮忙排查下。

问题核心现象

每次发起Apple登录请求后,进入回调阶段都会抛出CSRF错误(state值不匹配)。我确认每次都是单次请求触发Apple登录,没有重复调用的情况,但登录前的Session和回调时的Session里,关联Apple的state字段就是对不上。

相关代码与配置细节

1. Apple登录与回调接口实现

async def login_with_apple(request):
    logger.debug(f"Session before Apple login: {request.session}")
    redirect_uri = Config.APPLE_REDIRECT_URI
    return await oauth.apple.authorize_redirect(request, redirect_uri)

async def apple_callback(request):
    logger.debug(f"Session at Apple callback: {request.session}")
    try:
        token = await oauth.apple.authorize_access_token(request)
        # 后续业务逻辑...

2. Session中间件配置

为了支持跨子域共享Session,我配置了如下中间件:

app.add_middleware(
    SessionMiddleware,
    secret_key=Config.SECRET_KEY,
    session_cookie="session",
    https_only=True,
    same_site="none",
    domain=".xyz.net",
)

3. Apple OAuth注册与密钥生成

不同于Google登录的静态密钥,Apple需要动态生成客户端密钥,我的配置如下:

# Apple OAuth 注册
oauth.register(
    name="apple",
    client_id=Config.APPLE_CLIENT_ID,
    client_secret=generate_apple_client_secret(),
    authorize_url="https://appleid.apple.com/auth/authorize",
    access_token_url="https://appleid.apple.com/auth/token",
    api_base_url="https://appleid.apple.com",
    client_kwargs={
        "scope": "name email",
        "response_mode": "form_post",
        "response_type": "code",
    },
)

# 动态生成Apple客户端密钥的函数
def generate_apple_client_secret():
    headers = {
        "kid": Config.APPLE_KEY_ID,
        "alg": "ES256"
    }
    payload = {
        "iss": Config.APPLE_TEAM_ID,
        "iat": int(datetime.utcnow().timestamp()),
        "exp": int((datetime.utcnow() + timedelta(days=180)).timestamp()),
        "aud": "https://appleid.apple.com",
        "sub": Config.APPLE_CLIENT_ID,
    }
    client_secret = jwt.encode(
        payload,
        Config.APPLE_PRIVATE_KEY,
        algorithm="ES256",
        headers=headers
    )
    return client_secret

已完成的验证项

  • Apple开发者后台的服务ID已配置主域名xyz.net和子域名api.xyz.net
  • 回调URLhttps://api.xyz.net/auth/callback/apple完全匹配代码与Apple后台配置
  • Session中间件的domain设置为.xyz.net,确保子域api.xyz.net能共享Session,same_site="none"和https_only=True也符合跨域场景要求

关键Session观察结果

回调时的Session内容如下,除了state值本身,其他参数(如redirect_uri、请求Apple的完整URL)都和发起登录时完全一致:

Session at Apple callback: {
    '_state_apple_ysgzefTXafasd3E9Z6DE914': {
        'data': {
            'redirect_uri': 'https://api.xyz.net/auth/callback/apple',
            'url': 'https://appleid.apple.com/auth/authorize?response_type=code&client_id=com.xyz.web&redirect_uri=https%3A%2F%2Fapi.xyz.net%2Fauth%2Fcallback%2Fapple&scope=name+email&state=ysgzefTX59ZhDdcgpHbF3E9Z6DE914&response_mode=form_post'
        },
        'exp': 1749759103.7634718
    }
}

注意到Session中存储的state键是_state_apple_ysgzefTXafasd3E9Z6DE914,但实际请求Apple时的state参数是ysgzefTX59ZhDdcgpHbF3E9Z6DE914,这两个state值无法匹配,最终导致CSRF验证失败。

目前实在摸不清问题出在哪,有没有遇到过类似场景的朋友?或者能给我一些排查方向建议的?

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 09:59:31