Skip to content

Commit

Permalink
4.6.4-alpha (#569)
Browse files Browse the repository at this point in the history
  • Loading branch information
c121914yu authored Dec 7, 2023
1 parent 71afe71 commit e01c38e
Show file tree
Hide file tree
Showing 80 changed files with 1,398 additions and 1,106 deletions.
172 changes: 134 additions & 38 deletions docSite/content/docs/development/openapi/share.md
Original file line number Diff line number Diff line change
@@ -1,94 +1,175 @@
---
title: '分享链接鉴权'
description: 'FastGPT 分享链接鉴权'
title: '分享链接身份鉴权'
description: 'FastGPT 分享链接身份鉴权'
icon: 'share'
draft: false
toc: true
weight: 860
---

## 介绍

在 FastGPT V4.6.4 中,我们修改了分享链接的数据读取方式,为每个用户生成一个 localId,用于标识用户,从云端拉取对话记录。但是这种方式仅能保障用户在同一设备同一浏览器中使用,如果切换设备或者清空浏览器缓存则会丢失这些记录。这种方式存在一定的风险,因此我们仅允许用户拉取近`30天``20条`记录。

分享链接身份鉴权设计的目的在于,将 FastGPT 的对话框快速、安全的接入到你现有的系统中,仅需 2 个接口即可实现。

## 使用说明

分享链接鉴权设计的目的在于,将 FastGPT 的对话框安全的接入你现有的系统中。
免登录链接配置中,你可以选择填写`身份验证`栏。这是一个`POST`请求的根地址。在填写该地址后,分享链接的初始化、开始对话以及对话结束都会向该地址的特定接口发送一条请求。下面以`host`来表示`凭身份验证根地址`。服务器接口仅需返回是否校验成功即可,不需要返回其他数据,格式如下:

免登录链接配置中,增加了`凭证校验服务器`后,使用分享链接时会向服务器发起请求,校验链接是否可用,并在每次对话结束后,向服务器发送对话结果。下面以`host`来表示`凭证校验服务器`。服务器接口仅需返回是否校验成功即可,不需要返回其他数据,格式如下:
### 接口统一响应格式

```json
{
"success": true,
"message": "错误提示",
"msg": "同message, 错误提示"
"msg": "同message, 错误提示",
"uid": "用户唯一凭证"
}
```

![](/imgs/sharelinkProcess.png)
`FastGPT` 将会判断`success`是否为`true`决定是允许用户继续操作。`message``msg`是等同的,你可以选择返回其中一个,当`success`不为`true`时,将会提示这个错误。

`uid`是用户的唯一凭证,将会用于拉取对话记录以及保存对话记录。可参考下方实践案例。

## 配置校验地址和校验token
### 触发流程

### 1. 配置校验地址的`BaseURL`
![](/imgs/sharelinkProcess.png)

## 配置教程
### 1. 配置身份校验地址

![](/imgs/share-setlink.jpg)

配置校验地址后,在每次分享链接使用时,都会向对应的地址发起校验和上报请求。

{{% alert icon="🤖" %}}
这里仅需配置根地址,无需具体到完整请求路径。
{{% /alert %}}

### 2. 分享链接中增加额外 query

在分享链接的地址中,增加一个额外的参数: authToken。例如:

原始的链接:https://fastgpt.run/chat/share?shareId=648aaf5ae121349a16d62192
完整链接: https://fastgpt.run/chat/share?shareId=648aaf5ae121349a16d62192&authToken=userid12345
原始的链接:`https://fastgpt.run/chat/share?shareId=648aaf5ae121349a16d62192`

这个`token`通常是你系统生成的,在发出校验请求时,FastGPT 会在`body`中携带 token={{authToken}} 的参数。
完整链接: `https://fastgpt.run/chat/share?shareId=648aaf5ae121349a16d62192&authToken=userid12345`

## 聊天初始化校验
这个`authToken`通常是你系统生成的用户唯一凭证(Token之类的)。FastGPT 会在鉴权接口的`body`中携带 token={{authToken}} 的参数。

**FastGPT 发出的请求**
### 3. 编写聊天初始化校验接口

{{< tabs tabTotal="3" >}}
{{< tab tabName="请求示例" >}}
{{< markdownify >}}

```bash
curl --location --request POST '{{host}}/shareAuth/init' \
--header 'Content-Type: application/json' \
--data-raw '{
"token": "sintdolore"
"token": "{{authToken}}"
}'
```

**响应示例**
{{< /markdownify >}}
{{< /tab >}}

{{< tab tabName="鉴权成功" >}}
{{< markdownify >}}

```json
{
"success": true,
"uid": "username123",
}
```

系统会拉取该分享链接下,uid 为 username123 的对话记录。

{{< /markdownify >}}
{{< /tab >}}

{{< tab tabName="鉴权失败" >}}
{{< markdownify >}}

```json
{
"success": false,
"message": "分享链接无效",
"message": "身份错误",
}
```

## 对话前校验
{{< /markdownify >}}
{{< /tab >}}
{{< /tabs >}}



**FastGPT 发出的请求**
### 4. 编写对话前校验接口

{{< tabs tabTotal="3" >}}
{{< tab tabName="请求示例" >}}
{{< markdownify >}}

```bash
curl --location --request POST '{{host}}/shareAuth/start' \
--header 'Content-Type: application/json' \
--data-raw '{
"token": "sintdolore",
"token": "{{authToken}}",
"question": "用户问题",
}'
```

**响应示例**
{{< /markdownify >}}
{{< /tab >}}

{{< tab tabName="鉴权成功" >}}
{{< markdownify >}}

```json
{
"success": true,
"uid": "username123",
}
```

{{< /markdownify >}}
{{< /tab >}}

{{< tab tabName="鉴权失败" >}}
{{< markdownify >}}

```json
{
"success": true
"success": false,
"message": "身份验证失败",
}
```

```json
{
"success": false,
"message": "存在违规词",
}
```

## 对话结果上报
{{< /markdownify >}}
{{< /tab >}}
{{< /tabs >}}

### 5. 编写对话结果上报接口(可选)

该接口无规定返回值。

响应值与[chat 接口格式相同](/docs/development/openapi/chat/#响应),仅多了一个`token`

可以重点关注`responseData`里的`price`值,`price`与实际价格的倍率为`100000`,即 100000=1元。

```bash
curl --location --request POST '{{host}}/shareAuth/finish' \
--header 'Content-Type: application/json' \
--data-raw '{
"token": "sint dolore",
"token": "{{authToken}}",
"responseData": [
{
"moduleName": "KB Search",
Expand Down Expand Up @@ -156,18 +237,18 @@ curl --location --request POST '{{host}}/shareAuth/finish' \
}'
```

响应值与 chat 接口相同,增加了一个 token。可以重点关注`responseData`里的值,price 与实际价格的倍率为`100000`

**此接口无需响应值**

## 使用示例
## 实践案例

我们以[Laf作为服务器为例](https://laf.dev/)展示这 3 个接口的使用方式。
我们以[Laf作为服务器为例](https://laf.dev/)简单展示这 3 个接口的使用方式。

### 1. 创建3个Laf接口

![](/imgs/share-auth1.jpg)



{{< tabs tabTotal="3" >}}
{{< tab tabName="/shareAuth/init" >}}
{{< markdownify >}}
Expand All @@ -179,13 +260,15 @@ import cloud from '@lafjs/cloud'

export default async function (ctx: FunctionContext) {
const { token } = ctx.body


// 此处省略 token 解码过程
if (token === 'fastgpt') {
return { success: true }
return { success: true, data: { uid: "user1" } }
}

return { success: false,message: "身份错误" }
return { success: false,message:"身份错误" }
}

```

{{< /markdownify >}}
Expand All @@ -201,8 +284,8 @@ import cloud from '@lafjs/cloud'

export default async function (ctx: FunctionContext) {
const { token, question } = ctx.body
console.log(token, question, 'start')

// 此处省略 token 解码过程
if (token !== 'fastgpt') {
return { success: false, message: "身份错误" }

Expand All @@ -212,8 +295,9 @@ export default async function (ctx: FunctionContext) {
return { success: false, message: "内容不合规" }
}

return { success: true }
return { success: true, data: { uid: "user1" } }
}

```

{{< /markdownify >}}
Expand All @@ -229,7 +313,12 @@ import cloud from '@lafjs/cloud'

export default async function (ctx: FunctionContext) {
const { token, responseData } = ctx.body
console.log(token,responseData,'=====')

const total = responseData.reduce((sum,item) => sum + item.price,0)
const amount = total / 100000

// 省略数据库操作

return { }
}
```
Expand All @@ -241,17 +330,24 @@ export default async function (ctx: FunctionContext) {

### 2. 配置校验地址

我们随便复制3个地址中一个接口https://d8dns0.laf.dev/shareAuth/finish , 去除 /shareAuth/finish 后填入 FastGPT 中: https://d8dns0.laf.dev
我们随便复制3个地址中一个接口: `https://d8dns0.laf.dev/shareAuth/finish`, 去除`/shareAuth/finish`后填入`身份校验`:`https://d8dns0.laf.dev`

![](/imgs/share-auth2.jpg)

### 3. 修改分享链接参数

源分享链接:[https://fastgpt.run/chat/share?shareId=64be36376a438af0311e599c](https://fastgpt.run/chat/share?shareId=64be36376a438af0311e599c)
源分享链接:`https://fastgpt.run/chat/share?shareId=64be36376a438af0311e599c`

修改后:[https://fastgpt.run/chat/share?shareId=64be36376a438af0311e599c&authToken=fastgpt](https://fastgpt.run/chat/share?shareId=64be36376a438af0311e599c&authToken=fastgpt)
修改后:`https://fastgpt.run/chat/share?shareId=64be36376a438af0311e599c&authToken=fastgpt`

### 4. 测试效果

1. 打开源链接或者`authToken`不等于 `fastgpt`的链接会提示身份错误。
2. 发送内容中包含你字,会提示内容不合规。
1. 打开源链接或者`authToken`不等于`fastgpt`的链接会提示身份错误。
2. 发送内容中包含你字,会提示内容不合规。


## 使用场景

这个鉴权方式通常是帮助你直接嵌入`分享链接`到你的应用中,在你的应用打开分享链接前,应做`authToken`的拼接后再打开。

除了对接已有系统的用户外,你还可以对接`余额`功能,通过`结果上报`接口扣除用户余额,通过`对话前校验`接口检查用户的余额。
8 changes: 7 additions & 1 deletion packages/global/common/error/code/outLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { ErrType } from '../errorCode';
export enum OutLinkErrEnum {
unExist = 'unExist',
unAuthLink = 'unAuthLink',
linkUnInvalid = 'linkUnInvalid'
linkUnInvalid = 'linkUnInvalid',

unAuthUser = 'unAuthUser'
}
const errList = [
{
Expand All @@ -19,6 +21,10 @@ const errList = [
code: 501,
statusText: OutLinkErrEnum.linkUnInvalid,
message: '分享链接无效'
},
{
statusText: OutLinkErrEnum.unAuthUser,
message: '身份校验失败'
}
];
export default errList.reduce((acc, cur, index) => {
Expand Down
33 changes: 0 additions & 33 deletions packages/global/core/chat/api.d.ts

This file was deleted.

6 changes: 6 additions & 0 deletions packages/global/core/chat/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ export const ChatSourceMap = {
}
};

export enum ChatStatusEnum {
loading = 'loading',
running = 'running',
finish = 'finish'
}

export const HUMAN_ICON = `/icon/human.svg`;
export const LOGO_ICON = `/icon/logo.svg`;

Expand Down
Loading

0 comments on commit e01c38e

Please sign in to comment.