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 - 回调URL
https://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
相关产品推荐
相关产品推荐

