# SSO & 外部成员同步

> FastGPT 外部成员系统接入设计与配置

Source: https://doc.fastgpt.cn/zh-CN/guide/admin/sso

如果你不需要用到 SSO/成员同步功能，或者是只需要用 Github、google、microsoft、公众号的快速登录，可以跳过本章节。本章适合需要接入自己的成员系统或主流办公 IM 的用户。

## 介绍

为了方便地接入**外部成员系统**，FastGPT 提供一套接入外部系统的**标准接口**，以及一个 FastGPT-SSO-Service 镜像作为**适配器**。

通过这套标准接口，你可以实现：

1. SSO 登录。从外部系统回调后，在 FastGPT 中创建一个用户。
2. 成员和组织架构同步（下面都简称成员同步）。

**原理**

FastGPT-pro 中，有一套标准的 SSO 和成员同步接口，系统会根据这套接口进行 SSO 和成员同步操作。

FastGPT-SSO-Service 是为了聚合不同来源的 SSO 和成员同步接口，将他们转成 fastgpt-pro 可识别的接口。

![通过适配服务完成 SSO 登录](/imgs/diagrams/sso-adapter.zh-CN.light.svg)

## 系统配置教程

### 1. 部署 SSO-service 镜像

使用 docker-compose 部署：

```yaml
fastgpt-sso:
  image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sso-service:latest
  container_name: fastgpt-sso
  restart: always
  networks:
    - fastgpt
  environment:
    - SSO_PROVIDER=example
    - AUTH_TOKEN=xxxxx # 鉴权信息，fastgpt-pro 会用到。
    # 具体对接提供商的环境变量。
```

根据不同的提供商，你需要配置不同的环境变量，下面是内置的通用协议/IM：

协议/功能
SSO
成员同步支持

飞书
是
是

企业微信
是
是

钉钉
是
否

Saml2.0
是
否

Oauth2.0
是
否

LDAP
否
是

### 2. 配置 fastgpt-pro

#### 1. 配置环境变量

环境变量中的 `EXTERNAL_USER_SYSTEM_BASE_URL` 为内网地址，例如上述例子中的配置，环境变量应该设置为

```yaml
env:
  - EXTERNAL_USER_SYSTEM_BASE_URL=http://fastgpt-sso:3000
  - EXTERNAL_USER_SYSTEM_AUTH_TOKEN=xxxxx
```

> 该地址由部署方通过环境变量配置，属于可信内部端点而非用户可控输入。SSO 授权、OAuth 回调与成员同步
> 都据此直连，不受 `CHECK_INTERNAL_IP` 影响；开启 `CHECK_INTERNAL_IP=true` 不会中断 SSO
> 登录与成员同步。

#### 2. 在 FastGPT 前台的 `管理员` -> `系统配置` -> `用户配置` 中配置按钮文字，图标等。

在“自定义用户系统配置”区域可查看只读的 SSO 服务地址，并设置 **SSO 登录按钮标题**、**SSO 登录按钮图标** 与 **自动跳转** 开关。下方三张品牌图标可直接下载并上传作为登录按钮图标：

企业微信
钉钉
飞书

![企业微信](/imgs/sso15.png)
![钉钉](/imgs/sso16.png)
![飞书](/imgs/sso17.png)

#### 3. 开启成员同步（可选）

如果需要同步外部系统的成员，请在 **管理员 → 系统配置 → 用户配置** 的 **团队模式设置** 下拉框中选择 **同步模式**（需已配置 `EXTERNAL_USER_SYSTEM_BASE_URL` 且商业版 License 具备 SSO 能力）。团队模式规则可参考：[团队模式说明文档](/zh-CN/guide/admin/teamMode)。

![3. 开启成员同步（可选）：界面示例](/imgs/optimized/sso1.png.webp)

#### 4. 可选配置

1. 自动定时成员同步

设置 fastgpt-pro 环境变量则可开启自动成员同步

```yaml
env:
  - 'SYNC_MEMBER_CRON=0 0 * * *' # Cron 表达式，每天 0 点执行，注意需要以 UTC （0时区）为准，例如如果设置北京时间 12:00 进行同步，则此处需要配置为 "0 4 * * *" (UTC 4:00执行)
```

## 内置 Provider 配置示例

### 飞书

#### 1. 参数获取

App ID 和 App Secret

进入开发者后台，点击企业自建应用，在凭证与基础信息页面查看应用凭证。

![1. 参数获取：界面示例](/imgs/optimized/sso3.png.webp)

#### 2. 权限配置

进入开发者后台，点击企业自建应用，在开发配置的权限管理页面开通权限。

![2. 权限配置：界面示例](/imgs/optimized/sso4.png.webp)

可以使用**批量导入/导出权限** 功能，导入如下权限配置:

```json
{
  "scopes": {
    "tenant": [
      "contact:user.phone:readonly",
      "contact:contact.base:readonly",
      "contact:department.base:readonly",
      "contact:department.organize:readonly",
      "contact:user.base:readonly",
      "contact:user.department:readonly",
      "contact:user.email:readonly",
      "contact:user.employee_id:readonly"
    ],
    "user": []
  }
}
```

注意：可访问的数据范围需要开启全员可见

#### 3. 重定向 URL

进入开发者后台，点击企业自建应用，在开发配置的安全设置中设置重定向 URL，重定向 URL 形如 `https://www.fastgpt.cn/login/provider` 前面的域名修改为部署后公开可访问的 fastgpt 的域名
![3. 重定向 URL：界面示例](/imgs/optimized/sso5.png.webp)

#### 4. yml 配置示例

```yaml
fastgpt-sso:
  image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sso-service:latest
  container_name: fastgpt-sso
  restart: always
  networks:
    - fastgpt
  environment:
    - SSO_PROVIDER=feishu
    - AUTH_TOKEN=xxxxx
    # oauth 接口（私有化部署的飞书改为私有化的地址, 下同）
    - SSO_TARGET_URL=https://accounts.feishu.cn/open-apis/authen/v1/authorize
    # 获取token 接口
    - FEISHU_TOKEN_URL=https://open.feishu.cn/open-apis/authen/v2/oauth/token
    # 获取用户信息接口
    - FEISHU_GET_USER_INFO_URL=https://open.feishu.cn/open-apis/authen/v1/user_info
    # 重定向地址，设置为上面第三步中一模一样的地址
    - FEISHU_REDIRECT_URI=https://www.fastgpt.cn/login/provider
    # 飞书APP的应用ID，一般以cli开头
    - FEISHU_APP_ID=xxx
    # 飞书APP的应用密钥
    - FEISHU_APP_SECRET=xxx
```

### 钉钉

#### 1. 参数获取

CLIENT_ID 与 CLIENT_SECRET

进入钉钉开放平台，点击应用开发，选择自己的应用进入，记录在凭证与基础信息页面下的 `Client ID` 与 `Client secret`。![1. 参数获取：界面示例](/imgs/optimized/sso6.png.webp)

#### 2. 权限配置

进入钉钉开放平台，点击应用开发，选择自己的应用进入，在开发配置的权限管理页面操作，需要开通的权限包括：

1. **_个人手机号信息_**
2. **_通讯录个人信息读权限_**
3. **_获取钉钉开放接口用户访问凭证的基础权限_**

#### 3. 重定向 URL

进入钉钉开放平台，点击应用开发，选择自己的应用进入，在开发配置的安全设置页面操作
需要填写的内容有两个：

1. 服务器出口 IP（调用钉钉服务端 API 的服务器 IP 列表）
2. 重定向 URL（回调域名）

#### 4. yml 配置示例

```yaml
fastgpt-sso:
  image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sso-service:latest
  container_name: fastgpt-sso
  restart: always
  networks:
    - fastgpt
  environment:
    - SSO_PROVIDER=dingtalk
    - AUTH_TOKEN=xxxxx
    #oauth 接口
    - SSO_TARGET_URL=https://login.dingtalk.com/oauth2/auth
    #获取token 接口
    - DINGTALK_TOKEN_URL=https://api.dingtalk.com/v1.0/oauth2/userAccessToken
    #获取用户信息接口
    - DINGTALK_GET_USER_INFO_URL=https://oapi.dingtalk.com/v1.0/contact/users/me
    #钉钉APP的应用ID
    - DINGTALK_CLIENT_ID=xxx
    #钉钉APP的应用密钥
    - DINGTALK_CLIENT_SECRET=xxx
```

### 企业微信

> 企微成员同步逻辑更新后，必须重新部署 `fastgpt-sso-service` 中转服务，并使用已发布的 `latest`
> 镜像。

#### 1. 参数获取

1. 企业的 CorpID

   a. 使用管理员账号登陆企业微信管理后台 `https://work.weixin.qq.com/wework_admin/loginpage_wx`

   b. 点击【我的企业】页面，查看企业的 **企业 ID**

   ![1. 参数获取：界面示例](/imgs/optimized/sso7.png.webp)

2. 创建一个供 FastGPT 使用的内部应用：

   a. 获取应用的 AgentID 和 Secret

   b. 应用的可见范围决定企微成员同步范围。请至少覆盖需要同步的部门；如果需要同步整个企业，请设置为根部门（全部可见）。

   ![1. 参数获取：界面示例](/imgs/optimized/sso8.png.webp)

   ![1. 参数获取：界面示例](/imgs/optimized/sso9.png.webp)

3. 一个域名。并且要求：

   a. 解析到可公网访问的服务器上

   b. 可以在该服务的根目录地址上挂载静态文件（以便进行域名归属认证，按照配置处的提示进行操作，只需要挂载一个静态文件，认证后可以删除）

   c. 配置网页授权，JS-SDK 以及企业微信授权登陆

   d. 可以在【企业微信授权登陆】页面下方设置"在工作台隐藏应用"

   ![1. 参数获取：界面示例](/imgs/optimized/sso10.png.webp)

   ![1. 参数获取：界面示例](/imgs/optimized/sso11.png.webp)

   ![1. 参数获取：界面示例](/imgs/optimized/sso12.png.webp)

4. 获取 "通讯录同步助手" secret

   获取通讯录，组织成员 ID 需要使用 "通讯录同步助手" secret

   【安全与管理】--【管理工具】--【通讯录同步】

   ![1. 参数获取：界面示例](/imgs/optimized/sso13.png.webp)

5. 开启接口同步

6. 获取 Secret

7. 配置企业可信 IP

   ![1. 参数获取：界面示例](/imgs/optimized/sso14.png.webp)

#### 2. 使用 latest 镜像部署 fastgpt-sso 中转服务

企微 SSO 登录使用应用的 Secret，成员同步使用“通讯录同步助手”的 Secret。请拉取已发布的 `latest` 镜像并重新创建服务：

```bash
docker compose pull fastgpt-sso
docker compose up -d --force-recreate fastgpt-sso
```

#### 3. yml 配置示例

```yaml
fastgpt-sso:
  image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sso-service:latest
  container_name: fastgpt-sso
  restart: always
  networks:
    - fastgpt
  environment:
    - AUTH_TOKEN=xxxxx
    - SSO_PROVIDER=wecom
    # oauth 接口，在企微终端使用
    - WECOM_TARGET_URL_OAUTH=https://open.weixin.qq.com/connect/oauth2/authorize
    # sso 接口，扫码
    - WECOM_TARGET_URL_SSO=https://login.work.weixin.qq.com/wwlogin/sso/login
    # 获取用户id（只能拿id)
    - WECOM_GET_USER_ID_URL=https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo
    # 获取用户详细信息（除了名字都有）
    - WECOM_GET_USER_INFO_URL=https://qyapi.weixin.qq.com/cgi-bin/auth/getuserdetail
    # 获取用户信息（有名字，没其他信息）
    - WECOM_GET_USER_NAME_URL=https://qyapi.weixin.qq.com/cgi-bin/user/get
    # 获取组织 id 列表
    - WECOM_GET_DEPARTMENT_LIST_URL=https://qyapi.weixin.qq.com/cgi-bin/department/list
    # 获取用户 id 列表
    - WECOM_GET_USER_LIST_URL=https://qyapi.weixin.qq.com/cgi-bin/user/list_id
    # 企微 CorpId
    - WECOM_CORPID=
    # 企微 App 的 AgentId 一般是 1000xxx
    - WECOM_AGENTID=
    # 企微 App 的 Secret
    - WECOM_APP_SECRET=
    # 通讯录同步助手的 Secret
    - WECOM_SYNC_SECRET=
```

#### 4. 企微成员同步规则

* `/org/list` 返回企微应用可见范围内的部门。
* `/user/list` 仍通过“通讯录同步助手”获取成员，但只保留至少属于一个应用可见部门的成员。
* 成员所属部门会同步过滤为应用可见部门；只属于不可见部门的成员不会同步到 FastGPT。
* 修改企微应用可见范围或镜像版本后，请重新执行一次成员同步；也可以先调用下方接口检查返回结果。

### 标准 OAuth2.0

我们提供一套 RFC 6749 中鉴权码模式的 OAuth2.0 接入支持。参考：

* [RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749) 文档。
* [阮一峰的网络日志](https://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html)

#### 参数需求

##### 三个地址

我们提供一套标准的 OAuth2.0 接入流程。需要三个地址：

1. 登陆鉴权地址（用户点击 SSO 按钮后将携带参数直接跳转到该地址）, 例如：`http://example.com/oauth/authorize`
   ```bash
   curl -X GET\
   "http://example.com/oauth/authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Ffastgpt.cn%2Flogin%2Fprovider"
   ```
   用户输入账号密码后，会跳转到 `redirect_uri` 中，并携带 `code` 参数，示例：
   ```text
   https://fastgpt.cn/login/provider?code=4/P7qD2qAz4&state=xyz
   ```
2. 获取 access_token 的地址，获取到 code 后，通过*服务器请求*该地址获取 access_token 例如：`http://example.com/oauth/access_token`
   ```bash
   curl -X POST\
       -H "Content-Type: application/x-www-form-urlencoded"\
   "http://example.com/oauth/access_token?grant_type=authorization_code&client_id=s6BhdRkqt3&client_secret=xxx&code=4/P7qD2qAz4&redirect_uri=https%3A%2F%2Ffastgpt.cn%2Flogin%2Fprovider"
   ```
   注意：Content-Type 必须是 application/x-www-form-urlencoded, 而不是 application/json
3. 获取用户信息的地址，需要传入 access_token 例如：`http://example.com/oauth/user_info`
   ```bash
   curl -X GET\
       -H "Authorization: Bearer 4/P7qD2qAz4"\
       "http://example.com/oauth/user_info"
   ```
   注意：access_token 作为 Authorization 头部传入, 格式为 Bearer xxxx

##### 参数配置

* CLIENT_ID: 必须
* CLIENT_SECRET: 非必须，如果没有可以不配置
* SCOPE: 非必须，如果没有可以不配置

> redirect_uri 参数会根据运行环境自动补全
>
> 其他固定参数如 grant_type, response_type 等会自动补全

#### 配置示例

```yaml
fastgpt-sso:
  image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sso-service:latest
  container_name: fastgpt-sso
  restart: always
  networks:
    - fastgpt
  environment:
    - SSO_PROVIDER=oauth2
    - AUTH_TOKEN=xxxxx
    # OAuth2.0
    # === 请求地址 ===
    # 1. OAuth2 登陆鉴权地址 (必填)
    - OAUTH2_AUTHORIZE_URL=
    # 2. OAuth2 获取 AccessToken 地址 (必填)
    - OAUTH2_TOKEN_URL=
    # 3. OAuth2 获取用户信息地址 (必填)
    - OAUTH2_USER_INFO_URL=
    # === 参数 ===
    # 1. client_id （必填）
    - OAUTH2_CLIENT_ID=
    # 2. client_secret (选填，如果没有则不传)
    - OAUTH2_CLIENT_SECRET=
    # 3. scope （选填）
    - OAUTH2_SCOPE=
    # === 字段映射 ===
    # OAuth2 用户名字段映射（必填）
    - OAUTH2_USERNAME_MAP=
    # OAuth2 头像字段映射（选填）
    - OAUTH2_AVATAR_MAP=
    # OAuth2 成员名字段映射(选填)
    - OAUTH2_MEMBER_NAME_MAP=
    # OAuth2 联系方式字段映射(选填)
    - OAUTH2_CONTACT_MAP=
```

### LDAP 用户和组织同步

LDAP provider 只负责同步用户和组织，不提供登录能力。推荐将登录 provider 与同步 provider 分开配置：

```yaml
fastgpt-sso:
  image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sso-service:latest
  environment:
    - SSO_PROVIDER=oauth2
    - SSO_SYNC_PROVIDER=ldap
    - AUTH_TOKEN=replace-with-a-sync-token
    - LDAP_URL=ldap://ldap.example.com:389
    - LDAP_BASE_DN=dc=example,dc=com
    - LDAP_BIND_DN=cn=fastgpt-sync,dc=example,dc=com
    - LDAP_BIND_PASSWORD=replace-with-readonly-password
    - LDAP_USER_BASE_DN=ou=people,dc=example,dc=com
    - LDAP_USER_FILTER=(&(objectClass=inetOrgPerson)(uid=*))
    - LDAP_USER_USERNAME_ATTRIBUTE=uid
    - LDAP_USER_MEMBER_NAME_ATTRIBUTE=displayName
    - LDAP_USER_CONTACT_ATTRIBUTE=mail
    - LDAP_USERNAME_PREFIX=ldap-
    - LDAP_MEMBERSHIP_MODE=user_attribute
    - LDAP_USER_ATTRIBUTE_ORG_BASE_DN=ou=company,dc=example,dc=com
    - LDAP_USER_ATTRIBUTE_ORG_FILTER=(objectClass=organizationalUnit)
    - LDAP_USER_ATTRIBUTE_ORG_NAME_ATTRIBUTE=ou
    - LDAP_USER_ATTRIBUTE_MEMBERSHIP_ATTRIBUTE=ou
    - LDAP_USER_ATTRIBUTE_MEMBERSHIP_VALUE_TYPE=name_or_dn
```

SSO_PROVIDER 继续负责登录，SSO_SYNC_PROVIDER=ldap 让 /user/list 和 /org/list 使用 LDAP。LDAP 不提供登录接口；如果仍需要 SSO 登录，不要将 SSO_PROVIDER 设置为 ldap。

#### FastGPT 侧配置

fastgpt-pro 需要访问 SSO-service，并使用与 SSO-service.AUTH_TOKEN 相同的 Token：

```yaml
env:
  - EXTERNAL_USER_SYSTEM_BASE_URL=http://fastgpt-sso:3000
  - EXTERNAL_USER_SYSTEM_AUTH_TOKEN=replace-with-a-sync-token
  - SYNC_MEMBER_CRON=0 0 * * *
```

然后在 FastGPT 前台的 `管理员` -> `系统配置` -> `用户配置` 中将 **团队模式设置** 切换为 **同步模式**。`SYNC_MEMBER_CRON` 使用 UTC 时区；留空表示不执行定时同步。

#### LDAP 连接配置

| 环境变量                            | 必填 | 默认值                                    | 说明                                      |
| ------------------------------- | -- | -------------------------------------- | --------------------------------------- |
| LDAP_URL                        | 是  | -                                      | 只支持 ldap\:// 或 ldaps\://，不能使用 https\:// |
| LDAP_BASE_DN                    | 是  | -                                      | 全局默认搜索基准 DN                             |
| LDAP_BIND_DN                    | 是  | -                                      | 只读同步账号 DN                               |
| LDAP_BIND_PASSWORD              | 是  | -                                      | 同步账号密码                                  |
| LDAP_USER_BASE_DN               | 否  | LDAP_BASE_DN                           | 用户搜索起点                                  |
| LDAP_USER_FILTER                | 否  | (&(objectClass=inetOrgPerson)(uid=\*)) | 用户过滤器                                   |
| LDAP_USER_USERNAME_ATTRIBUTE    | 否  | uid                                    | 用户唯一标识属性                                |
| LDAP_USER_MEMBER_NAME_ATTRIBUTE | 否  | displayName                            | 成员显示名属性                                 |
| LDAP_USER_CONTACT_ATTRIBUTE     | 否  | mail                                   | 联系方式属性                                  |
| LDAP_USER_AVATAR_ATTRIBUTE      | 否  | 空                                      | 头像属性，留空则不同步                             |
| LDAP_USERNAME_PREFIX            | 否  | ldap-                                  | 同步用户名的前缀                                |
| LDAP_PAGE_SIZE                  | 否  | 500                                    | LDAP 分页大小                               |
| LDAP_TIMEOUT_MS                 | 否  | 10000                                  | LDAP 操作超时，单位毫秒                          |
| LDAP_CONNECT_TIMEOUT_MS         | 否  | 10000                                  | LDAP 连接超时，单位毫秒                          |

使用 ldaps\:// 时，可以配置 LDAP_TLS_REJECT_UNAUTHORIZED、LDAP_TLS_CA_FILE、LDAP_TLS_CA、LDAP_TLS_CERT_FILE、LDAP_TLS_KEY_FILE 和 LDAP_TLS_SERVERNAME。私有 CA 建议使用 LDAP_TLS_CA_FILE；客户端证书和私钥必须同时配置。

#### 成员关系模式

模式
用户和组织的关系
主要配置

user_attribute
用户属性（默认 ou）指向组织
LDAP_USER_ATTRIBUTE\_\*

group_member_dn
组属性（默认 member）记录用户 DN
LDAP_GROUP_MEMBER_DN\_\*

user_member_of
用户属性（默认 memberOf）记录组 DN
LDAP_USER_MEMBER_OF\_\*

posix_member_uid
组属性（默认 memberUid）记录用户标识
LDAP_POSIX_MEMBER_UID\_\*

**1. user_attribute：用户属性映射组织**

```dotenv
LDAP_MEMBERSHIP_MODE=user_attribute
LDAP_USER_ATTRIBUTE_ORG_BASE_DN=ou=company,dc=example,dc=com
LDAP_USER_ATTRIBUTE_ORG_FILTER=(objectClass=organizationalUnit)
LDAP_USER_ATTRIBUTE_ORG_NAME_ATTRIBUTE=ou
LDAP_USER_ATTRIBUTE_MEMBERSHIP_ATTRIBUTE=ou
LDAP_USER_ATTRIBUTE_MEMBERSHIP_VALUE_TYPE=name_or_dn
```

name_or_dn 会先按组织 DN 匹配，匹配不到时再按组织名称匹配。

**2. group_member_dn：组记录用户 DN**

```text
dn: cn=engineering,ou=groups,dc=example,dc=com
objectClass: groupOfNames
cn: engineering
member: uid=alice,ou=people,dc=example,dc=com
```

```dotenv
LDAP_MEMBERSHIP_MODE=group_member_dn
LDAP_GROUP_MEMBER_DN_ORG_BASE_DN=ou=groups,dc=example,dc=com
LDAP_GROUP_MEMBER_DN_ORG_FILTER=(objectClass=groupOfNames)
LDAP_GROUP_MEMBER_DN_ORG_NAME_ATTRIBUTE=cn
LDAP_GROUP_MEMBER_DN_MEMBER_ATTRIBUTE=member
LDAP_GROUP_MEMBER_DN_MEMBER_VALUE_TYPE=dn
```

使用 groupOfUniqueNames 时，将过滤器改为 objectClass=groupOfUniqueNames，并通常将成员属性改为 uniqueMember。

**3. user_member_of：用户记录组 DN**

```dotenv
LDAP_MEMBERSHIP_MODE=user_member_of
LDAP_USER_MEMBER_OF_ORG_BASE_DN=ou=groups,dc=example,dc=com
LDAP_USER_MEMBER_OF_ORG_FILTER=(objectClass=groupOfNames)
LDAP_USER_MEMBER_OF_ORG_NAME_ATTRIBUTE=cn
LDAP_USER_MEMBER_OF_MEMBERSHIP_ATTRIBUTE=memberOf
LDAP_USER_MEMBER_OF_MEMBERSHIP_VALUE_TYPE=dn
```

该模式要求用户条目存在 memberOf 属性。部分 OpenLDAP 部署需要配置 memberof overlay。

**4. posix_member_uid：POSIX 组记录用户 uid**

```text
dn: cn=engineering,ou=groups,dc=example,dc=com
objectClass: posixGroup
cn: engineering
memberUid: alice
```

```dotenv
LDAP_MEMBERSHIP_MODE=posix_member_uid
LDAP_POSIX_MEMBER_UID_ORG_BASE_DN=ou=groups,dc=example,dc=com
LDAP_POSIX_MEMBER_UID_ORG_FILTER=(objectClass=posixGroup)
LDAP_POSIX_MEMBER_UID_ORG_NAME_ATTRIBUTE=cn
LDAP_POSIX_MEMBER_UID_MEMBER_ATTRIBUTE=memberUid
LDAP_POSIX_MEMBER_UID_USER_ID_ATTRIBUTE=uid
LDAP_POSIX_MEMBER_UID_MEMBER_VALUE_TYPE=username
```

#### 同步结果和限制

* 组织 ID 使用规范化后的 LDAP DN，parentId 根据 DN 层级自动推导。
* 如果最终组织列表存在多个无父级组织，会自动插入 ID 为 ldap-virtual-root、名称为 ROOT 的虚拟根。
* 用户结果使用 orgs 保存组织 ID；同步用户名默认为 ldap- 加 LDAP 用户标识。
* 登录 provider 返回的用户名必须使用相同的前缀和标识规则。
* 当前不递归展开嵌套组，也不解析动态组。

#### 手动检查同步接口

```bash
curl -H 'Authorization: Bearer replace-with-a-sync-token' http://fastgpt-sso:3000/org/list
curl -H 'Authorization: Bearer replace-with-a-sync-token' http://fastgpt-sso:3000/user/list
```

## 标准接口文档

以下是 FastGPT-pro 中，SSO 和成员同步的标准接口文档，如果需要对接非标准系统，可以参考该章节进行开发。

![第三方直接实现 SSO 标准接口](/imgs/diagrams/sso-direct.zh-CN.light.svg)

FastGPT 提供如下标准接口支持：

1. [https://example.com/login/oauth/getAuthURL](https://example.com/login/oauth/getAuthURL) 获取鉴权重定向地址
2. [https://example.com/login/oauth/getUserInfo?code=xxxxx](https://example.com/login/oauth/getUserInfo?code=xxxxx) 消费 code，换取用户信息
3. [https://example.com/org/list](https://example.com/org/list) 获取组织列表
4. [https://example.com/user/list](https://example.com/user/list) 获取成员列表

### 获取 SSO 登录重定向地址

返回一个重定向登录地址，fastgpt 会自动重定向到该地址。redirect_uri 会自动拼接到该地址的 query 中。

#### 请求示例

```bash
curl -X GET "https://redirect.example/login/oauth/getAuthURL?redirect_uri=xxx&state=xxxx" \
-H "Authorization: Bearer your_token_here" \
-H "Content-Type: application/json"
```

#### 响应示例

成功：

```json
{
  "success": true,
  "message": "",
  "authURL": "https://example.com/somepath/login/oauth?redirect_uri=https%3A%2F%2Ffastgpt.cn%2Flogin%2Fprovider%0A"
}
```

失败：

```json
{
  "success": false,
  "message": "错误信息",
  "authURL": ""
}
```

### SSO 获取用户信息

该接口接受一个 code 参数作为鉴权，消费 code 返回用户信息。

#### 请求示例

```bash
curl -X GET "https://oauth.example/login/oauth/getUserInfo?code=xxxxxx" \
-H "Authorization: Bearer your_token_here" \
-H "Content-Type: application/json"
```

#### 响应示例

成功：

```json
{
  "success": true,
  "message": "",
  "username": "fastgpt-123456789",
  "avatar": "https://example.webp",
  "contact": "+861234567890",
  "memberName": "成员名（非必填）"
}
```

失败：

```json
{
  "success": false,
  "message": "错误信息",
  "username": "",
  "avatar": "",
  "contact": ""
}
```

### 获取组织

#### 请求示例

```bash
curl -X GET "https://example.com/org/list" \
-H "Authorization: Bearer your_token_here" \
-H "Content-Type: application/json"
```

#### 响应示例

⚠️注意：只能存在一个根部门。如果你的系统中存在多个根部门，需要先进行处理，加一个虚拟的根部门。返回值类型：

```ts
type OrgListResponseType = {
  message?: string; // 报错信息
  success: boolean;
  orgList: {
    id: string; // 部门的唯一 id
    name: string; // 名字
    parentId: string; // parentId，如果为根部门，传空字符串。
  }[];
};
```

```json
{
  "success": true,
  "message": "",
  "orgList": [
    {
      "id": "od-125151515",
      "name": "根部门",
      "parentId": ""
    },
    {
      "id": "od-51516152",
      "name": "子部门",
      "parentId": "od-125151515"
    }
  ]
}
```

### 获取成员

#### 请求示例

```bash
curl -X GET "https://example.com/user/list" \
-H "Authorization: Bearer your_token_here" \
-H "Content-Type: application/json"
```

#### 响应示例

返回值类型：

```typescript
type UserListResponseListType = {
  message?: string; // 报错信息
  success: boolean;
  userList: {
    username: string; // 唯一 id username 必须与 SSO 接口返回的用户 username 相同。并且必须携带一个前缀，例如: sync-aaaaa，和 sso 接口返回的前缀一致
    memberName?: string; // 名字，作为 tmbname
    avatar?: string;
    contact?: string; // email or phone number
    orgs?: string[]; // 人员所在组织的 ID。没有组织传 []
  }[];
};
```

响应示例

```json
{
  "success": true,
  "message": "",
  "userList": [
    {
      "username": "fastgpt-123456789",
      "memberName": "张三",
      "avatar": "https://example.webp",
      "contact": "+861234567890",
      "orgs": ["od-125151515", "od-51516152"]
    },
    {
      "username": "fastgpt-12345678999",
      "memberName": "李四",
      "avatar": "",
      "contact": "",
      "orgs": ["od-125151515"]
    }
  ]
}
```

## 如何对接非标准系统

1. 客户自己开发：按 FastGPT 提供的标准接口进行开发，并通过环境变量 `EXTERNAL_USER_SYSTEM_BASE_URL` 配置部署后的服务地址（`管理员` -> `系统配置` -> `用户配置` 中只读展示该服务地址）
   可以参考该模版库：[fastgpt-sso-template](https://github.com/labring/fastgpt-sso-template) 进行开发
2. 由 fastgpt 团队定制开发：a. 提供系统的 SSO 文档、获取成员和组织的文档、以及外网测试地址。b. 在 fastgpt-sso-service 中，增加对应的 provider 和环境变量，并编写代码来对接。
