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

相关推荐
缘木之鱼1 小时前
CTFshow __Web应用安全与防护 第二章
前端·安全·渗透·ctf·ctfshow
沛沛老爹1 小时前
从Web到AI:多模态Agent Skills生态系统实战(Java+Vue构建跨模态智能体)
java·前端·vue.js·人工智能·rag·企业转型
子非鱼9211 小时前
Vue框架快速上手
前端·javascript·vue.js
winfredzhang1 小时前
从零构建:基于 Node.js 与 ECharts 的量化交易策略模拟系统
前端·node.js·echarts·股票·策略
We་ct1 小时前
LeetCode 380. O(1) 时间插入、删除和获取随机元素 题解
前端·算法·leetcode·typescript
LawrenceLan1 小时前
Flutter 零基础入门(二十三):Icon、Image 与资源管理
开发语言·前端·flutter·dart
津津有味道2 小时前
WEB浏览器网页读写Desfire EV1 EV2 EV3卡,修改DES、3DES、AES密钥JS源码JavaScript
前端·javascript·nfc·desfire·ev2·ev3·ev1
敲敲了个代码2 小时前
前端指纹技术是如何实现的?(Canvas、Audio、硬件API 核心原理解密)
前端·javascript·学习·算法·面试·web
Amumu121382 小时前
Vue简介
前端·javascript·vue.js
放逐者-保持本心,方可放逐2 小时前
React核心组件 及 钩子函数应用
前端·javascript·react.js·非阻塞更新·延迟更新·同步更新