实现iframe重定向通知父级页面跳转

需求: 在登录页面通过iframe嵌入钉钉提供的登录页面,用户扫码登录成功后,回到系统首页

问题: 钉钉登录页面授权登录后会携带一个code重定向到预设好的url路径,但是因为它是嵌入在iframe中的,所以重定向后的页面也是嵌入在iframe里面,这显然不是我们期望看到的。

解决思路:

  1. 钉钉授权登录成功后,重定向到一个中转页面
  2. 中转页面使用postMessage携带code通知父页面
  3. 父页面通过window.addEventListener('message')监听消息,并验证消息来源
  4. 父页面监听到消息,并验证成功后,处理code,将code发送给后台转为token
  5. 接收到后台发送回的token,登录成功,隐藏iframe并跳转首页

参考文档:
使用钉钉提供的页面登录授权
一文搞懂window.postMessage和window.parent.postMessage

实现代码:

js 复制代码
// 中转页面
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>钉钉登录中转</title>
    <script>
      // 钉钉登录回调页面
      window.addEventListener("load", () => {
        // 从URL参数中获取授权码
        const code = new URLSearchParams(window.location.search).get("code");
        if (code) {
          // 发送消息给父页面
          console.log("发送消息给父页面", code);
          window.parent.postMessage(
            {
              type: "DINGTALK_LOGIN_REDIRECT",
              code: code,
            },
            window.location.origin
          );
        }
      });
    </script>
  </head>
</html>
js 复制代码
// 父页面部分html代码
<div class="ding-talk" v-if="useDingtalkLogin">
  <el-button class="normal-login" @click="changeLoginType('general')">普通登录</el-button>
  <iframe :src="ddLoginUrl" width="100%" height="100%"></iframe>
</div>
<div v-else>
    // 普通登录页面
</div>
js 复制代码
// 父页面逻辑代码【vue2】
mounted() {
  this.initMessageListener();
},
beforeDestroy() {
  window.removeEventListener("message", this.handleMessage);
},
methods:{
  // 初始化消息监听
  initMessageListener() {
    window.addEventListener("message", this.handleMessage);
  },
  // 处理接收到的消息
  handleMessage(event) {
    console.log("event.origin", event.origin, window.location.origin);
    if (event.origin !== window.location.origin) {
      console.log("忽略来自未知来源的消息:", event.origin);
      return;
    }
    // 验证消息格式
    if (event.data && event.data.type === "DINGTALK_LOGIN_REDIRECT") {
      console.log("收到钉钉登录重定向消息:", event.data);
      this.handleDingtalkLogin(event.data.code);
    }
  },
  handleDingtalkLogin(code) {
    // 处理code的逻辑...
    this.useDingtalkLogin = false;  // 隐藏iframe
  },
}
相关推荐
JarvanMo3 分钟前
Flutter 3.38 + Firebase:2025 年开发者必看的新变化
前端
Lethehong12 分钟前
简历优化大师:基于React与AI技术的智能简历优化系统开发实践
前端·人工智能·react.js·kimi k2·蓝耘元生代·蓝耘maas
华仔啊21 分钟前
还在用 WebSocket 做实时通信?SSE 可能更简单
前端·javascript
鹏北海42 分钟前
多标签页登录状态同步:一个简单而有效的解决方案
前端·面试·架构
_AaronWong1 小时前
基于 Vue 3 的屏幕音频捕获实现:从原理到实践
前端·vue.js·音视频开发
孟祥_成都1 小时前
深入 Nestjs 底层概念(1):依赖注入和面向切面编程 AOP
前端·node.js·nestjs
let_code1 小时前
CopilotKit-丝滑连接agent和应用-理论篇
前端·agent·ai编程
Apifox1 小时前
Apifox 11 月更新|AI 生成测试用例能力持续升级、JSON Body 自动补全、支持为响应组件添加描述和 Header
前端·后端·测试
木易士心1 小时前
深入剖析:按下 F5 后,浏览器前端究竟发生了什么?
前端·javascript
在掘金801101 小时前
vue3中使用medium-zoom
前端·vue.js