飞书网页应用免登(SSO)

一、需求描述

最近有个需求实现网页应用在飞书客户端内的免登操作并获取用户信息,相关飞书文档:https://open.feishu.cn/document/quickly-create-a-login-free-web-app/introduction

最初看到示例代码(https://open.feishu.cn/document/quickly-create-a-login-free-web-app/introduction-to-sample-code),看起来是挺简单的过程。但这里有个坑,就是示例代码跟简介里面的流程是不一样的:

实际示例代码的免登流程应该是这样的:https://open.feishu.cn/document/client-docs/h5/development-guide/step-3

示例代码是通过在客户端调用tt.requestAccess来获取临时授权code(官方推荐),而简介里是通过跳转授权链接再重定向URL携带授权码的方式。

飞书上的文档看似详细,但隐藏的问题也是需要注意的(后面会提到相关问题),这方面现在的资料比较少,因此记录起来分析给大家。

下面,也是使用示例代码的方式来实现飞书网页应用免登(SSO)。

二、代码实现

复制代码
<template>
  <div class="app">
      <!-- 加载状态 -->
      <div v-if="loading" class="loading-container">
        加载中
      </div>
  </div>
</template>

<script setup>
import { ref, onMounted, watch } from 'vue';
import { showToast } from 'vant';

// 状态管理
const loading = ref(false);

// 飞书免登录流程
const initFeishuLodinAuth = async () => {
  try {
    // 检查是否在飞书客户端内
    if (!window.h5sdk && !window.tt) {
      console.log('invalid h5sdk');
      showToast('please open in feishu');
      return;
    }
    
    // 通过服务端的get_appid获取app_id
    // 为了安全,app_id不应对外泄露,尤其不应在前端明文书写,因此此处从服务端获取
    const appIdResponse = await fetch('/feishu/shenpi/getAppId');
    const appIdRes = await appIdResponse.json();
    const appId = appIdRes.data.appId;
    
    // 通过error接口处理API验证失败后的回调
    window.h5sdk.error(err => {
        throw('h5sdk error:', JSON.stringify(err));
    });

    // 初始化JSSDK
    await new Promise((resolve, reject) => {
      window.h5sdk.ready(() => {
        resolve();
      });
    });
    
    // 获取免登临时授权码
    // 注意:根据文档,应该使用tt.requestAcces
    const code = await new Promise((resolve, reject) => {
      tt.requestAccess({
        appID: appId,
        scopeList: [],
        success: (res) => {
          console.log('requestAccess success:', res);
          resolve(res.code);
        },
        fail: (err) => {
          reject(err);
        }
      });
    });
    
    // 向服务端发送code获取用户信息
    const userResponse = await fetch(`/feishu/shenpi/ssoLogin?code=${code}`);
    
    const userResData = await userResponse.json();
    console.log('userResData:', userResData);
    if (userResData.code == 200) {
      isLoggedIn.value = true;
      console.log('登录成功:', userResData.data);
    } else {
      showToast('登录失败,请重试');
    }
  } catch (error) {
    console.error('免登流程失败:', error);
    showToast('免登失败,请重试');
  }
};

// 页面加载时初始化
onMounted(async () => {
  // 开始加载,显示加载动画
  loading.value = true;
  
  try {
    // 执行免登录流程
    await initFeishuLodinAuth();

  } finally {
    // 结束加载,隐藏加载动画
    loading.value = false;
  }
  
});
</script>

<style scoped>
.app {
  height: 100vh;
  display: flex;
  flex-direction: column;
  background-color: #f5f5f5;
}
</style>

三、问题记录

  1. Error code: 20029; error message: invalid redirect uri in h5 case 请求不合法

在飞书客户端打开测试网页应用,可能会遇到以下报错:

复制代码
errCode: 999
errMsg: "requestAccess:fail please check errno"
errno: 2700002
errString: "Authorization terminated unexpectedly. Error code: 20029; error message: invalid redirect uri in h5 case 请求不合法"

解决方案:

网页应用配置http://xxx.xxx.xxx:3000

需要在飞书开发者后台安全设置中正确设置重定向URL,由于是测试,所以这边设置了本地IP地址:http://xxx.xxx.xxx:3000/,注意这个地址是你调用tt.requestAccess的网页地址(建议在当前页面调用 window.location.href.split('?')[0].split('#')[0] 来获取重定向 URL),具体规则可以查看https://open.feishu.cn/document/develop-web-apps/configure-redirect-urls

IP 白名单、H5 可信域名也相应配置一下。

特别注意:如果是http://xxx.xxx.xxx:3000/,不要遗漏路径最后面的那个/,否则还会报那个错!!!

相关推荐
观无16 小时前
若依EasyExcel实现单元格合并
开发语言·前端·javascript
愚公搬代码17 小时前
【愚公系列】《Web应用安全》001-VMware的安装
前端·安全
xiaohaiAIgeo17 小时前
【2026年】HG/T 20656-2024化工暖通空调设计规范:新版标准的变化与影响
java·前端·javascript·科普知识
立少→万能汉编17 小时前
用“立少→超文本”写静态网页,标签<倍>
服务器·前端·javascript
weixin_4316004417 小时前
NestJS 入门(7):生命周期钩子——构造函数和 `OnModuleInit` 差在哪?
前端·后端·学习·node.js·nest.js
你挚爱的强哥17 小时前
【chromeDownload】自定义组件:多用于登录框底部提供下载Chrome谷歌浏览器的链接
前端·vue.js·chrome
cindershade18 小时前
用原生 HTML5 视频与 Canvas 实现浏览器端视频抽帧封面
前端
笨鸟先飞,勤能补拙18 小时前
Web 服务器与计算机网络全景原理
运维·服务器·前端·网络·人工智能·计算机网络·web安全
NutShell Wang18 小时前
Wails v3 Beta 实战:用显式对象模型重写你的第一个 Go 桌面应用
前端·人工智能·go·vibe coding
cindershade18 小时前
前端国际化工程实践:语言包拆分、动态加载与日期数字格式统一
前端