18586361686
2025-05-27 60f92fd9afc5eb34998f248c51403129d3313d46
feat: iframe 匿名用户访问功能
docs: 匿名用户访问 iframe 文档
2个文件已修改
2个文件已添加
124 ■■■■ 已修改文件
aiflowy-modules/aiflowy-module-system/src/main/java/tech/aiflowy/system/controller/SysTempTokenController.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
aiflowy-ui-react/src/pages/ExternalBot.tsx 66 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/.vitepress/config.mts 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
docs/zh/product/system/iframe.md 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
aiflowy-modules/aiflowy-module-system/src/main/java/tech/aiflowy/system/controller/SysTempTokenController.java
New file
@@ -0,0 +1,31 @@
package tech.aiflowy.system.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import tech.aiflowy.common.constant.Constants;
import tech.aiflowy.common.domain.Result;
import tech.aiflowy.common.entity.LoginAccount;
import java.math.BigInteger;
@RestController
@RequestMapping("/api/temp-token")
public class SysTempTokenController {
    @GetMapping("/create")
    @SaIgnore
    public Result createTempToken() {
        StpUtil.login(0);
        String tokenValue = StpUtil.getTokenValue();
        LoginAccount loginAccount = new LoginAccount();
        loginAccount.setId(BigInteger.valueOf(0));
        loginAccount.setLoginName("匿名用户");
        StpUtil.getSession().set(Constants.LOGIN_USER_KEY, loginAccount);
        return Result.success(tokenValue);
    }
}
aiflowy-ui-react/src/pages/ExternalBot.tsx
@@ -2,7 +2,7 @@
    Conversations, ConversationsProps,
} from '@ant-design/x';
import { createStyles } from 'antd-style';
import React, { useEffect, useState } from 'react';
import React, {useEffect, useRef, useState} from 'react';
import {
    DeleteOutlined,
    EditOutlined, ExclamationCircleFilled,
@@ -93,10 +93,37 @@
export const ExternalBot: React.FC = () => {
    const urlParams = new URLSearchParams(location.search);
    const token = urlParams.get('authKey');
    if (token) {
        localStorage.setItem('authKey', token);
    }
    const [isExternalIFrame, setIsExternalIFrame] = useState<boolean>(false);
    const isExternalIFrameRef = useRef(isExternalIFrame);
   const {doGet: doGetCreateToken} =  useGetManual('/api/temp-token/create')
    useEffect(() => {
        isExternalIFrameRef.current = isExternalIFrame;
    }, [isExternalIFrame]);
    useEffect(() => {
        const isFrame = urlParams.get('isIframe');
        const token = urlParams.get('authKey');
        if (isFrame) {
            const newValue = true;
            setIsExternalIFrame(newValue);
            isExternalIFrameRef.current = newValue; // 手动同步 ref
            doGetCreateToken().then((res: any) => {
                if (res.data.errorCode === 0){
                    localStorage.setItem('authKey', res.data.data);
                    const link = document.querySelector("link[rel*='icon']") as HTMLLinkElement;
                    doGetBotInfo({params: {id: params?.id}}).then((r: any) => {
                        if (link) {
                            link.href = r?.data?.data?.icon || '/favicon.png';
                        }
                        document.title = r?.data?.data?.title;
                    });
                }
            });
        } else if (token) {
                localStorage.setItem('authKey', token);
        }
    }, []); // 空依赖数组表示只在组件挂载时执行一次
    const [newTitle, setNewTitle] = useState<string>('');
    // ==================== Style ====================
@@ -171,17 +198,24 @@
        }
        return [];
    };
    useEffect(() => {
        if (chats.length === 2 && chats[1].content.length < 1){
            getConversationManualGet({
                params:  { "botId": params?.id }
            }).then((r: any) => {
                setConversationsItems(getConversations(r?.data?.data?.cons));
            });
        }
    }, [chats]);
     useEffect(() => {
         if (isExternalIFrameRef.current) {
             return;
         }
            if (chats.length === 2 && chats[1].content.length < 1){
                getConversationManualGet({
                    params:  { "botId": params?.id }
                }).then((r: any) => {
                    setConversationsItems(getConversations(r?.data?.data?.cons));
                });
            }
        }, [chats])
    useEffect(() => {
        if (isExternalIFrameRef.current) {
            return;
        }
        const link = document.querySelector("link[rel*='icon']") as HTMLLinkElement;
        doGetBotInfo({params: {id: params?.id}}).then((r: any) => {
            if (link) {
@@ -199,7 +233,7 @@
            setActiveKey(getExternalSessionId());
            setConversationsItems(getConversations(r?.data?.data?.cons));
        });
    }, []);
    }, [])
    const onAddConversation = () => {
        setNewExternalSessionId();
@@ -271,7 +305,7 @@
    };
    // ==================== Render ====================
    return (
        <div className={styles.layout}>
       <div className={styles.layout}>
            <Modal
                title="修改会话名称"
                open={open}
docs/.vitepress/config.mts
@@ -284,6 +284,10 @@
                    link: 'system/apiKey.md',
                },
                {
                    text: 'iframe 嵌入',
                    link: 'system/iframe.md',
                },
                {
                    text: '数据字典',
                    link: 'system/data_dictionary.md',
                },
docs/zh/product/system/iframe.md
New file
@@ -0,0 +1,23 @@
# iframe 嵌入
## 不携带 token 嵌入
不携带 token, 客户端将不展现任何后台聊天记录
参数解析:
http://localhost:8899/ai/externalBot/281900928474001408?isIframe=true<br/>
访问的 Bot 的id : 281900928474001408<br/>
前端网页地址: http://localhost:8899/ai/externalBot/<br/>
需要携带固定参数 **isIframe=true**
请求示例如下:
```js
<iframe id="testFrame" src="http://localhost:8899/ai/externalBot/281900928474001408?isIframe=true"></iframe>
```
## 携带 token 嵌入
携带 token, 客户端将展现该用户的后台聊天记录
authKey: 需要后台管理页面生成访问页面的 token
请求示例如下:
```js
<iframe id="testFrame" src="http://localhost:8899/ai/externalBot/281900928474001408?authKey=xxxxxx"></iframe>
```