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

Angular应用中Apple Login在Safari浏览器无法正常工作

Apple登录在Safari中无法传递redirect URI的解决方案

问题根源

Safari对Apple登录有特殊处理机制:会拦截window.open触发的跳转,替换为原生的「Sign in with Apple」触控弹窗。这种情况下,原逻辑依赖的window.opener关联会失效,导致redirect页面无法通过postMessage向主页面传递code等数据。


解决方案1:修复现有逻辑并适配Safari场景

第一步:修正Angular代码的语法错误

原代码存在字符串拼接语法错误,且未对redirect_uri做URL编码,先修复这两点:

// 原错误代码
// const openNewWindow = window.open( 'https://appleid.apple.com/auth/authorize?response_type=code&response_mode=form_post&scope=name%20email&state=W4cL2JgRJq&client_id=CLIENT_ID&redirect_uri='+ this.AppleURL',"_blank" );

// 修正后代码
try {
  const authUrl = `https://appleid.apple.com/auth/authorize?response_type=code&response_mode=form_post&scope=name%20email&state=W4cL2JgRJq&client_id=CLIENT_ID&redirect_uri=${encodeURIComponent(this.AppleURL)}`;
  const openNewWindow = window.open(authUrl, "_blank");
  
  // 移除重复的message监听,避免多次触发
  const signInWithAppleHandler = (event) => {
    try {
      this.signInWithApple(JSON.parse(event.data));
      window.removeEventListener('message', signInWithAppleHandler);
      window.removeEventListener('storage', storageHandler);
    } catch (e) {
      console.error('解析登录数据失败', e);
    }
  };
  window.addEventListener('message', signInWithAppleHandler);

  // 新增storage监听,适配Safari原生弹窗场景
  const storageHandler = (event) => {
    if (event.key === 'appleLoginData') {
      const data = JSON.parse(event.newValue);
      this.signInWithApple(data);
      localStorage.removeItem('appleLoginData');
      window.removeEventListener('storage', storageHandler);
      window.removeEventListener('message', signInWithAppleHandler);
    }
  };
  window.addEventListener('storage', storageHandler);

  if (openNewWindow) {
    openNewWindow.opener = window;
  } else {
    // 若window.open被拦截(Safari原生弹窗触发),直接在当前页面跳转
    window.location.href = authUrl;
  }
} catch (error) {
  console.error("打开Apple登录页面失败", error);
}

第二步:修改重定向页面的传递逻辑

在redirect页面中增加localStorage fallback逻辑,应对Safari无法获取window.opener的情况:

<script>
function proceedPostToken() {
  var data = { "code": '{{apple_code}}', "firstName": '{{first_name}}', "lastName": '{{last_name}}'};
  
  if (window.ReactNativeWebView) { 
    window.ReactNativeWebView.postMessage(JSON.stringify(data));
    window.close();
  } else if (window.opener) {
    window.opener.postMessage(JSON.stringify(data), '*'); 
    window.close();
  } else {
    // Safari原生弹窗场景,用localStorage传递数据
    localStorage.setItem('appleLoginData', JSON.stringify(data));
    // 尝试关闭弹窗,若无效则跳转回主页面(需保证同域)
    window.close() || (window.location.href = '你的主页面地址');
  }
}
proceedPostToken();
</script>

关键注意点

  • 主页面和redirect URI必须同域,否则localStorage和window.opener都会被浏览器的同源策略限制。
  • 确保Apple开发者后台中配置的redirect URI和代码中完全一致(包括编码后的格式)。

解决方案2:使用Apple官方JS SDK(推荐)

官方SDK会自动适配所有浏览器的差异,包括Safari的原生弹窗,无需手动处理跳转和数据传递逻辑:

  1. 在页面引入SDK:
<script type="text/javascript" src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script>
  1. Angular中调用登录:
// 初始化授权配置
const appleAuth = new window.AppleID.auth({
  clientId: 'CLIENT_ID',
  scope: 'name email',
  redirectURI: this.AppleURL,
  state: 'W4cL2JgRJq'
});

// 发起登录请求
appleAuth.signIn().then((response) => {
  // 直接获取code和用户信息
  this.signInWithApple({
    code: response.code,
    firstName: response.user?.name?.firstName,
    lastName: response.user?.name?.lastName
  });
}).catch((error) => {
  console.error('Apple登录失败', error);
});

这种方式无需依赖redirect页面的postMessage或localStorage,SDK会自动处理所有兼容性问题。

内容的提问来源于stack exchange,提问作者aman singh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 06:44:53