PWA中Sign in with Apple跳转空白页问题及修复方案咨询
Apple登录手机端跳转至redirect_uri空白页的修复方案
问题背景
已实现Sign in with Apple功能,手机端测试时会跳转到配置的redirect_uri对应的空白页面。调试跟踪Apple JS SDK发现,SDK会动态创建FORM元素,将POST目标设为redirect_uri并触发提交,导致页面导航到该URL并显示POST响应(后端未返回可视内容,所以显示空白)。
现有代码问题
首先注意后端代码里的小错误:audience: '<client_id' 缺少闭合单引号,应该改为audience: '<client_id>',否则会导致token验证失败。
修复方案
方案1:启用弹窗模式(推荐)
开启usePopup: true参数后,Apple授权流程会在弹窗中完成,不会触发页面跳转,授权结果通过AppleIDSignInOnSuccess/AppleIDSignInOnFailure事件回调返回,完全符合前端无跳转的需求。
修改前端初始化代码:
AppleID.auth.init({ clientId : '<client_id>', scope : 'email', redirectURI : 'mySite.com/apple_auth', state : 'origin:web', nonce : Date.now(), usePopup : true // 启用弹窗模式 })
注意:需要确保前端页面允许弹窗,浏览器弹窗拦截设置要放行当前域名。
方案2:后端返回重定向
如果不想使用弹窗模式,后端在完成token验证后,需要重定向回前端原页面,并通过URL参数传递授权结果状态,前端再根据参数处理后续逻辑。
修改后端POST接口:
app.express.post('/apple_auth', async (req, res)=>{ var body = req.body try { const appleRes = await appleSignin.verifyIdToken( body.id_token, { audience: '<client_id>', // 修复引号缺失问题 ignoreExpiration: true, } ) // 验证成功,重定向回前端页面,携带必要参数 const encodedUser = encodeURIComponent(JSON.stringify(appleRes)) res.redirect('/?apple_auth=success&user=' + encodedUser) } catch (err) { console.error(err) // 验证失败,重定向回前端并携带错误信息 res.redirect('/?apple_auth=error&msg=' + encodeURIComponent(err.message)) } })
前端需要在页面加载时检查URL参数,处理授权结果:
// 页面初始化时检查 window.addEventListener('load', () => { const params = new URLSearchParams(window.location.search) if (params.get('apple_auth') === 'success') { const user = JSON.parse(decodeURIComponent(params.get('user'))) // 处理用户登录逻辑 console.log('Apple登录成功', user) // 可选:清除URL参数,避免刷新页面重复处理 window.history.replaceState({}, document.title, window.location.pathname) } else if (params.get('apple_auth') === 'error') { const msg = decodeURIComponent(params.get('msg')) console.error('Apple登录失败', msg) } })
方案3:拦截SDK的form提交(应急方案)
通过监听DOM变化捕获SDK动态创建的FORM元素,阻止其默认提交行为,改用AJAX提交表单数据,避免页面跳转。
添加前端代码:
// 监听body下的DOM变化,捕获SDK创建的form const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.addedNodes.length) { const appleForm = document.querySelector('form[action="mySite.com/apple_auth"]') if (appleForm) { appleForm.addEventListener('submit', (e) => { e.preventDefault() // 阻止默认跳转 // 手动提交表单数据 fetch(appleForm.action, { method: 'POST', body: new FormData(appleForm), credentials: 'include' }) .then(res => res.json()) .then(data => { // 处理后端返回的验证结果 console.log('Apple授权结果', data) // 可以手动触发成功事件,兼容原有回调 const successEvent = new CustomEvent('AppleIDSignInOnSuccess', { detail: { data: data } }) document.dispatchEvent(successEvent) }) .catch(err => { console.error('提交失败', err) const failEvent = new CustomEvent('AppleIDSignInOnFailure', { detail: { error: err } }) document.dispatchEvent(failEvent) }) }) observer.disconnect() // 只需要拦截一次,监听完成后断开 } } }) }) observer.observe(document.body, { childList: true, subtree: true })
注意:这种方式依赖SDK的DOM结构,若Apple更新SDK实现,可能失效,仅作为临时应急方案。
内容的提问来源于stack exchange,提问作者vaid
相关产品推荐
相关产品推荐

