飞书网页应用免登(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/,不要遗漏路径最后面的那个/,否则还会报那个错!!!

相关推荐
ModyQyW41 分钟前
HBuilderX 4.87 无法正常读取 macOS 环境配置的解决方案
前端·uni-app
bitbitDown1 小时前
我的2025年终总结
前端
五颜六色的黑1 小时前
vue3+elementPlus实现循环列表内容超出时展开收起功能
前端·javascript·vue.js
wscats2 小时前
Markdown 编辑器技术调研
前端·人工智能·markdown
EnoYao2 小时前
Markdown 编辑器技术调研
前端·javascript·人工智能
JIngJaneIL2 小时前
基于java+ vue医院管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot
JIngJaneIL2 小时前
基于java + vue校园跑腿便利平台系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot
前端要努力2 小时前
月哥创业3年,还活着!
前端·面试·全栈
sao.hk3 小时前
ubuntu2404安装k3s
前端·chrome
cos3 小时前
Worktrunk 完全指南:让 Git Worktree 和 Claude Code 和平共处
前端·ai编程·claude