产品介绍
VanCone Passport 是覆盖企业组织和个人用户全场景的统一身份认证和权限管控服务,集成了通用的 SSO 单点登录和 RBAC 鉴权机制,旨在为用户提供账户注册与登录、授权鉴权等功能。用户在 Passport 平台上注册账号之后,就相当于持有统一的服务通行证,可以登录使用所有集成 Passport 认证的应用服务。各个业务应用无需单独构建登录和鉴权能力,用户在不同应用之间跳转也无需重复登录。
欢迎体验 Passport 服务:
- 生产环境:https://passport.vancone.com/admin
- 测试环境:http://passport.beta.vancone.com/admin (仅限内网访问)

核心特性
统一身份认证
- 支持邮箱注册、密码登录
- 登录需通过滑块验证码,防止自动化攻击
- 邮箱验证码机制,用于找回密码
- 支持 JWT Token 认证,采用 ES256 算法
- 基于 Cookie 和 Header 双重 Token 传递机制
- 连续登录失败超限自动锁定账号
SSO 单点登录
- 用户一次登录,多个应用无缝切换
- 支持同域 Cookie 共享实现单点登录
- Token 采用无状态 JWT,有效期固定为 24 小时,不提供续期机制,过期后需重新登录
RBAC 权限管控
- 基于角色的访问控制(Role-Based Access Control)
- 支持租户级别的多租户隔离
- 精细化的 API 级别权限控制
- 支持账号与群组的权限绑定
管理后台
- 可视化管理界面,操作简便
- 租户管理、账号管理、群组管理、权限管理、应用管理一体化
- 登录历史记录追踪
多账号类型支持
- 个人账号:普通用户账号,用于登录使用应用
- 应用账号:服务账号,用于应用服务之间的 API 调用认证
用户痛点
Passport 重点分析目标用户的需求和痛点,并推出了高效可靠、易于落地推广的解决方案。
普通用户痛点
- 访问不同应用需要登录不同账号
- 多套账号密码不方便记忆,更容易存在泄漏风险
- 跨应用切换时需要重复登录
管理员痛点
- 账号和权限持续维护难度大
- 新员工入职、离职时权限配置繁琐
- 缺乏统一的用户身份管理平台
应用开发者痛点
- 需要为每个应用重复开发登录注册模块,工作量大
- 不同应用之间相互调用,没有统一的授权/鉴权机制
- 安全防护很难面面俱到,容易受到攻击等安全威胁
- 权限管理逻辑复杂,容易出错
应用场景
账号注册和登录
- 注册账号后即可登录,无需邮箱激活
- 使用用户名/邮箱和密码登录,登录前需完成滑块验证码
- Token 认证,支持跨应用免登录
安全验证和防护
- 滑块验证码,用于登录与找回密码
- 邮箱验证码机制,用于找回密码
- JWT Token 签名验证
- API 级别的权限控制
- 登录历史记录追踪
权限分配
- 管理员统一分配权限
- 支持个人权限和群组权限
- 灵活的权限组合策略
应用注册和发布
- 应用开发者注册应用
- 定义应用的 API 接口清单
- 创建应用账号,获取 Access Key
- 关联权限到 API 接口
开发集成和部署
- 提供 Java SDK(Spring Boot)与 Go SDK(Gin)简化集成
- 提供公开 REST API
- 支持本地缓存机制
- 支持同步应用下的 API 与权限配置
系统架构

Passport 平台主要由以下模块组成:
| 模块 | 说明 |
|---|---|
| 管理后台 | Vue 3 + TypeScript 构建,提供可视化的管理界面 |
| 认证服务 | passport-service,处理用户登录、注册、Token 签发与验证等核心功能 |
| 管理服务 | passport-admin,提供租户、账号、群组、权限、应用等管理 API |
| SDK | Java SDK(Spring Boot)与 Go SDK(Gin),简化应用接入认证鉴权功能 |
| 数据存储 | 使用 MySQL 存储业务数据,Redis 缓存验证码与 Token 相关数据 |
账号类型
Passport 支持两种类型的账号:
个人账号
用于真人用户登录系统,具有以下特点:
- 支持邮箱登录
- 需要密码验证
- 可以绑定到多个群组
- 可以分配多个权限
应用账号
用于服务之间的 API 调用认证,具有以下特点:
- 通过 Access Key ID / Secret Access Key 认证
- 关联到具体的应用
- 用于服务间通信,无需人工登录
- 支持创建和管理多个凭证
鉴权模型
Passport 采用 RBAC(基于角色的访问控制)模型,鉴权链路如下:
User(用户)
↓
Group(群组)/ Account(账号)
↓
Permission(权限)
↓
API(接口)
- 用户:最终使用系统的用户
- 群组/账号:用户的集合,可以批量分配权限
- 权限:API 接口的集合,表示一组操作能力
- API:具体的服务接口,是权限控制的原子单位
认证机制
Passport 采用无状态 JWT 作为认证凭据。服务端不保存会话(Session),所有身份信息都封装在 Token 中,由持有公钥的一方在本地完成校验。
早期版本中基于服务端会话(
sessionId+passport_sessionCookie)的认证方式已在 Go 版本中移除,当前不存在任何 Session 相关接口。
Token 概述
| 项目 | 说明 |
|---|---|
| 类型 | JWT(JSON Web Token) |
| 签名算法 | ES256(ECDSA + SHA-256),服务端硬编码,不可配置 |
| 有效期 | 签发后 24 小时,固定值,不支持续期 |
| 传递方式 | Cookie passport_token,或请求头 passport-token |
Claims 结构
| Claim | 说明 |
|---|---|
acid | 账号 ID(雪花 ID) |
uid | 用户 ID,即登录名 |
tid | 租户 ID |
pids | 权限 ID 数组 |
exp | 过期时间戳 |
Token 过期后需重新登录(个人账号)或重新申请(应用账号)。
认证方式一:用户名 / 密码登录
适用于真人用户通过页面或客户端登录的场景。
流程
1. 获取滑块验证码 GET /api/passport/service/v1/verify/image
2. 校验滑块验证码 POST /api/passport/service/v1/verify/image → captchaToken
3. 登录 POST /api/passport/service/v1/login → token
第一步:调用「生成滑块验证码」接口,获取底图、拼图块与缺口位置。
第二步:采集用户拖动滑块的落点坐标,以表单格式(point 为 "x,y")连同 key 提交,换取 captchaToken。校验容差为 4 像素。
第三步:携带 captchaToken、登录名(userId 或 email)与密码调用登录接口。
captchaToken是登录的必填参数。未携带或校验未通过时,登录接口直接返回10005 Captcha verification failed,不会校验密码。
登录成功
- 响应体中返回
token与username - 同时下发两个 Cookie:
passport_token(Token)与passport_username(用户名或登录名),有效期由服务端配置决定(默认 86400 秒)
登录失败
登录失败不返回 HTTP 错误码,而是返回 HTTP 200 并在 body 中携带业务错误码,接入方必须解析 code 判断:
| 业务码 | 说明 |
|---|---|
| 10001 | 账号不存在 |
| 10002 | 密码错误 |
| 10003 | 连续失败次数超限,账号已锁定 |
| 10004 | 账号已禁用 |
| 10005 | 滑块验证码校验失败 |
连续失败超过服务端配置的阈值(默认 5 次)后账号被锁定;登录成功后失败计数清零。密码以 BCrypt 存储与比对。
登出
调用 DELETE /api/passport/service/v1/login 清除客户端 Cookie。由于服务端无状态,登出不会使 Token 立即失效,已签发的 Token 在过期前仍可通过校验。
认证方式二:AK / SK 换取 Token
适用于服务间调用(应用账号)的场景,无需人工登录。
流程
1. 生成签名 POST /api/passport/service/v1/token/signature → signature + timestamp
2. 换取 Token POST /api/passport/service/v1/token → token
第一步:提交 accessKeyId 与 secretAccessKey,服务端返回签名与毫秒时间戳。签名算法为:
signature = UPPER(HEX(HMAC-SHA256(secretAccessKey, accessKeyId + timestamp)))
第二步:提交 accessKeyId、timestamp、signature 换取 Token。服务端会重新计算签名比对,并校验应用账号凭证是否存在。
使用 SDK 时,上述两步与 Token 缓存均由 SDK 内部完成,无需手动调用。Go SDK 的 Token 缓存周期为 3600 秒。
服务端如何校验请求
passport-service 按下述顺序处理每一个请求:
- 请求路径命中配置的鉴权路径模式时进入校验,否则直接放行
- 注册接口(
POST /account)与找回密码接口(/account/forgot-password/*)显式豁免 - 优先从 Cookie
passport_token读取 Token,为空时读取请求头passport-token - 校验签名与有效期
- 校验通过则将
acid/uid/tid/pids写入请求上下文供后续处理使用;校验失败返回 HTTP 401 与{"code":11002,"message":"Not authorized"}
业务服务接入时无需自行实现上述逻辑,直接使用 SDK 提供的中间件即可,参见「SDK 集成(Java)」与「SDK 集成(Go)」。
修改密码
当前版本不提供已登录状态下的修改密码接口。修改密码请通过「找回密码」流程完成:滑块验证码 → 邮箱验证码 → 重置密码。详见「公开接口」的 Forgot Password 模块。
接入方注意:调用
PUT /api/passport/service/v1/account更新账号时,请求体中不要携带password字段。该接口为全量保存,明文密码会覆盖数据库中的 BCrypt 密文,导致账号永久无法登录。
基础操作
基础操作面向普通用户,介绍如何注册账号、登录系统以及使用个人中心管理自己的信息。
注册账号
注册账号需要提供邮箱地址和用户自定义密码。注册完成后即可登录,无需邮箱激活。
注册步骤
- 访问 Passport 注册页面
- 填写注册信息:
- 用户名(登录标识,全局唯一)
- 邮箱地址(用于找回密码)
- 密码
- 确认密码
- 点击「注册」按钮
- 注册完成,跳转到登录页

注意事项
- 用户名必须唯一,不能与已有账号重复
- 密码需要满足一定的复杂度要求(长度不少于 8 位,包含大小写字母、数字和特殊字符)
- 邮箱地址必须真实有效——它是后续找回密码的唯一途径
- 密码复杂度目前仅由页面前端校验
登录账号
账号注册完成后,即可使用用户名或邮箱登录系统。
登录步骤
- 访问 Passport 登录页面
- 输入用户名或邮箱地址、密码
- 完成滑块验证码:拖动滑块,将拼图块对齐到缺口位置
- 点击「登录」按钮

滑块验证码是登录的必经环节。未通过验证将无法提交登录,服务端会直接返回「验证码校验失败」,不会校验密码。
登录失败与账号锁定
连续登录失败超过 5 次后,账号会被锁定,需等待管理员处理或联系技术支持。登录成功后失败计数清零。
可能出现的结果:
| 提示 | 说明 |
|---|---|
| 账号不存在 | 用户名或邮箱未注册 |
| 密码错误 | 密码不正确 |
| 账号已锁定 | 连续失败次数超限 |
| 账号已禁用 | 账号被管理员停用 |
| 验证码校验失败 | 滑块验证码未通过或已失效 |
扫码登录
登录页支持扫码登录:页面展示一张动态二维码,使用已登录的 VanCone App 扫码并在手机上确认后,网页自动完成登录并跳转回来源页面。
操作步骤
- 在登录页切换到扫码登录
- 打开 VanCone App,使用扫一扫识别页面上的二维码
- 在手机上确认登录
- 网页显示「登录成功」后自动跳转,无需输入账号密码
二维码状态
| 状态 | 说明 |
|---|---|
| 等待扫码 | 二维码有效,等待 App 扫码 |
| 已扫码 | App 已识别二维码,等待用户在手机上确认 |
| 登录成功 | 确认完成,网页自动跳转 |
| 二维码已过期 | 二维码有效期为 120 秒,过期后点击「点击刷新」重新获取 |
注意事项
- 二维码一次性有效,确认登录后立即作废,不能重复使用
- 二维码过期后原码作废,必须刷新后重新扫码
- 扫码登录会记录在登录历史中,登录方式为「扫码」
- App 端扫码功能在后续版本提供,发布前扫码入口暂不可完成确认操作
单点登录
当用户登录 Passport 后,会获得一个有效的 Token。该 Token 通过 Cookie 和 Header 两种方式传递给后续访问的应用。已集成 Passport 的应用会自动识别该 Token,实现免登录访问,这就是 SSO 单点登录机制。
Token 有效期
Token 有效期为登录后 24 小时,不支持自动续期。过期后需要重新登录。
登出账号
用户可以主动退出登录,清除本地 Token。
登出步骤
- 在任意已集成的应用中找到「登出」按钮
- 点击后系统会清除 Token
- 退出后需要重新登录才能访问受保护的资源
找回密码
如果用户忘记密码,可以通过注册邮箱找回。找回流程为「滑块验证码 → 邮箱验证码 → 重置密码」三段式。
找回步骤
- 在登录页面点击「忘记密码」
- 完成滑块验证码
- 输入注册邮箱地址,系统发送验证码邮件
- 打开邮件,输入邮件中的验证码
- 设置新密码并提交
注意事项
- 只能通过注册邮箱找回密码
- 邮箱验证码和重置凭证都有时效性,请尽快完成
- 重置密码后原密码立即失效
- 已登录状态下的「修改密码」功能当前版本未提供,忘记密码时请使用本流程
基础操作
基础操作面向普通用户,介绍如何注册账号、登录系统以及使用个人中心管理自己的信息。
注册账号
注册账号需要提供邮箱地址和用户自定义密码。注册完成后即可登录,无需邮箱激活。
注册步骤
- 访问 Passport 注册页面
- 填写注册信息:
- 用户名(登录标识,全局唯一)
- 邮箱地址(用于找回密码)
- 密码
- 确认密码
- 点击「注册」按钮
- 注册完成,跳转到登录页

注意事项
- 用户名必须唯一,不能与已有账号重复
- 密码需要满足一定的复杂度要求(长度不少于 8 位,包含大小写字母、数字和特殊字符)
- 邮箱地址必须真实有效——它是后续找回密码的唯一途径
- 密码复杂度目前仅由页面前端校验
登录账号
账号注册完成后,即可使用用户名或邮箱登录系统。
登录步骤
- 访问 Passport 登录页面
- 输入用户名或邮箱地址、密码
- 完成滑块验证码:拖动滑块,将拼图块对齐到缺口位置
- 点击「登录」按钮

滑块验证码是登录的必经环节。未通过验证将无法提交登录,服务端会直接返回「验证码校验失败」,不会校验密码。
登录失败与账号锁定
连续登录失败超过 5 次后,账号会被锁定,需等待管理员处理或联系技术支持。登录成功后失败计数清零。
可能出现的结果:
| 提示 | 说明 |
|---|---|
| 账号不存在 | 用户名或邮箱未注册 |
| 密码错误 | 密码不正确 |
| 账号已锁定 | 连续失败次数超限 |
| 账号已禁用 | 账号被管理员停用 |
| 验证码校验失败 | 滑块验证码未通过或已失效 |
扫码登录
登录页支持扫码登录:页面展示一张动态二维码,使用已登录的 VanCone App 扫码并在手机上确认后,网页自动完成登录并跳转回来源页面。
操作步骤
- 在登录页切换到扫码登录
- 打开 VanCone App,使用扫一扫识别页面上的二维码
- 在手机上确认登录
- 网页显示「登录成功」后自动跳转,无需输入账号密码
二维码状态
| 状态 | 说明 |
|---|---|
| 等待扫码 | 二维码有效,等待 App 扫码 |
| 已扫码 | App 已识别二维码,等待用户在手机上确认 |
| 登录成功 | 确认完成,网页自动跳转 |
| 二维码已过期 | 二维码有效期为 120 秒,过期后点击「点击刷新」重新获取 |
注意事项
- 二维码一次性有效,确认登录后立即作废,不能重复使用
- 二维码过期后原码作废,必须刷新后重新扫码
- 扫码登录会记录在登录历史中,登录方式为「扫码」
- App 端扫码功能在后续版本提供,发布前扫码入口暂不可完成确认操作
单点登录
当用户登录 Passport 后,会获得一个有效的 Token。该 Token 通过 Cookie 和 Header 两种方式传递给后续访问的应用。已集成 Passport 的应用会自动识别该 Token,实现免登录访问,这就是 SSO 单点登录机制。
Token 有效期
Token 有效期为登录后 24 小时,不支持自动续期。过期后需要重新登录。
登出账号
用户可以主动退出登录,清除本地 Token。
登出步骤
- 在任意已集成的应用中找到「登出」按钮
- 点击后系统会清除 Token
- 退出后需要重新登录才能访问受保护的资源
找回密码
如果用户忘记密码,可以通过注册邮箱找回。找回流程为「滑块验证码 → 邮箱验证码 → 重置密码」三段式。
找回步骤
- 在登录页面点击「忘记密码」
- 完成滑块验证码
- 输入注册邮箱地址,系统发送验证码邮件
- 打开邮件,输入邮件中的验证码
- 设置新密码并提交
注意事项
- 只能通过注册邮箱找回密码
- 邮箱验证码和重置凭证都有时效性,请尽快完成
- 重置密码后原密码立即失效
- 已登录状态下的「修改密码」功能当前版本未提供,忘记密码时请使用本流程
个人中心
个人中心是用户查看和管理个人信息的地方,包含个人资料、账号信息与登录历史三个标签页。
个人资料
对应「用户资料(Account Profile)」,与账号本身相互独立。
可查看与修改的字段
| 字段 | 说明 | 是否可修改 |
|---|---|---|
| 头像 | 用户头像图片 | 是,支持 jpg / jpeg / png / gif |
| 姓名 | 展示用的姓名 | 是 |
| 性别 | 男 / 女 / 其他 | 是 |
| 生日 | 生日信息 | 是 |
| 个人简介 | 一段自由文本,最多 200 字 | 是 |
修改个人资料
- 登录后进入个人中心的「个人资料」标签页
- 需要修改头像时,点击「上传头像」选择图片文件
- 修改其他字段后点击「保存」提交
邮箱与手机号不属于个人资料,请在「账号信息」标签页中修改。
账号信息
对应「账号(Account)」。
可查看与修改的字段
| 字段 | 说明 | 是否可修改 |
|---|---|---|
| 用户名 | 登录系统使用的唯一标识 | 否 |
| 账号类型 | 个人账号 / 应用账号 | 否 |
| 邮箱 | 注册时填写的邮箱地址,找回密码时使用 | 是 |
| 手机号 | 绑定的手机号码 | 是 |
| 所属租户 | 账号归属的租户 | 否 |
| 上次登录时间 | 最近一次登录的时间 | 否 |
修改账号信息
- 进入个人中心的「账号信息」标签页
- 修改邮箱或手机号
- 点击「保存」提交
注意事项:
- 用户名是登录标识,创建后不可修改
- 修改邮箱后,找回密码将发送到新邮箱,请确保新邮箱真实有效
登录历史
系统会记录用户每次登录的详细信息:
| 字段 | 说明 |
|---|---|
| 客户端 IP | 登录来源的 IP 地址 |
| 登录时间 | 登录操作的时间 |
| 登录方式 | WEB(页面登录)、API(应用账号换取 Token)或 QR_CODE(扫码登录) |
查看登录历史
- 进入个人中心
- 切换到「登录历史」标签页
- 查看最近的登录记录
登录历史可以帮助用户:
- 发现异常登录行为
- 追溯账号使用情况
- 进行安全审计
修改密码
当前版本不支持在个人中心修改密码。 请改用登录页的「忘记密码」流程。
找回密码流程
- 在登录页面点击「忘记密码」
- 完成滑块验证码
- 输入注册邮箱,接收邮件验证码
- 输入邮件中的验证码
- 设置新密码
详细说明见「基础操作」的找回密码章节,接口说明见「公开接口」的 Forgot Password 模块。
密码要求
- 长度不少于 8 位
- 包含大小写字母、数字和特殊字符
密码复杂度目前仅在页面前端校验,服务端不做强制约束。通过接口直接注册或重置密码时,请接入方自行校验。
账号安全建议
- 使用强密码:避免使用简单密码或个人信息
- 关注登录历史:定期查看登录记录,发现异常及时处理
- 保护邮箱安全:邮箱是找回密码的唯一途径,务必保护好
- 注意登录锁定:连续登录失败超过 5 次账号会被锁定,成功登录后计数清零
验证服务
Passport 当前提供滑块验证码与邮箱验证码两种验证方式。
人机验证(滑块验证码)
用于确认操作者是真人而非自动化程序,是登录与找回密码的必经环节。

交互流程
- 前端调用「生成滑块验证码」接口,获取底图、拼图块与缺口位置
- 用户拖动滑块,前端采集落点坐标
- 前端调用「校验滑块验证码」接口,提交落点坐标与验证码标识
- 校验通过后返回
captchaToken,该票据用于后续登录或找回密码请求
校验规则
- 落点横坐标与缺口位置相差不超过 4 像素即视为通过
captchaToken为一次性凭证,使用后即失效- 验证码有时效性,过期后需重新获取
适用范围
| 场景 | 是否需要滑块验证码 |
|---|---|
| 用户登录 | 是 |
| 找回密码(发送邮件验证码) | 是 |
| 账号注册 | 否 |
接口说明见「公开接口」的 Verify 模块。
邮件验证
用于确认操作者拥有该邮箱的控制权,通过向邮箱发送数字验证码实现。

适用范围
| 场景 | 是否需要邮箱验证码 |
|---|---|
| 找回密码 | 是 |
| 账号注册 | 否。注册后即可登录,账号没有待激活状态 |
找回密码中的使用
- 完成滑块验证码后,提交邮箱,系统发送验证码邮件
- 提交邮件中的验证码进行校验,换取
resetToken - 携带
resetToken与新密码完成重置
注意:邮箱验证码不用于注册流程。当前版本的注册接口不会消费邮箱验证码,注册完成后账号立即可用。
接口说明见「公开接口」的 Verify 与 Forgot Password 模块。
高阶操作
Passport 管理面为企业内部管理员提供账号、群组、权限、应用、租户的一站式管理服务。

管理菜单概览
管理后台提供以下功能模块:
| 菜单 | 功能 | 说明 |
|---|---|---|
| 账号 | 账号管理 | 管理个人账号和应用账号 |
| 群组 | 群组管理 | 管理用户群组及其权限 |
| 权限 | 权限管理 | 管理权限及其关联的 API |
| 应用 | 应用管理 | 管理应用及其 API 和权限 |
| 租户 | 租户管理 | 管理租户及其管理员 |
鉴权机制
从访问者角度
鉴权机制由以下几个要素构成:
User(用户) → Group/Account(群组/账号) → Permission(权限) → API(服务接口)
用户访问某个应用时,该应用通过一个接口粒度的清单来确定该用户是否具有访问权限。为了使用户和服务接口之间的映射集合更加方便管理,在二者之间又抽象出 Group(群组)和 Permission(权限)的概念:
- Group(群组):用户的集合,可以批量分配权限
- Permission(权限):API 接口的集合,表示一组操作能力
当用户通过页面访问服务时,页面请求调用将带上用户的 Token 到达后台服务,后台根据 Token 向 Passport 平台进行查询,获取该用户的权限集合,再和本地 Passport SDK 缓存的权限-接口清单进行比对,从而确定用户是否具备访问权限,如果不具备将直接返回 403 状态码。
如果用户首次访问某个应用,需要先由管理员将该用户加入相应的群组,或直接为该账号分配权限,使其具备所需访问权限。
系统内置的唯一权限为 passport_admin,拥有该权限的账号即为平台管理员,可以管理全部租户的数据:
| 权限名称 | 风险级别 | 描述 |
|---|---|---|
| passport_admin | 高风险 | 平台管理员 |
其余权限(例如
passport-operator、passport-reader)并非系统内置,需要管理员在「权限管理」中自行创建后再分配。上表中的名称仅为推荐的命名方式。
从应用服务角度
鉴权机制由以下几个要素构成:
Application(应用) → API(接口)→ Permission(权限)→ Group/Account(群组/账号)
应用服务首先在 Passport 平台上建立自己的虚拟账户(应用账号),并以 AK / SK 凭证进行认证访问。开发者需要将服务的接口清单事先注册到平台上,并关联具体的权限。每个权限都有自己的所属应用。
账号管理
账号类型
系统支持两种类型的账号:
| 类型 | 说明 | 典型场景 |
|---|---|---|
| 个人账号 | 真人用户使用的账号 | 普通用户登录应用 |
| 应用账号 | 服务之间调用的账号 | 服务间 API 通信 |
个人账号管理
个人账号包含以下信息:
| 字段 | 说明 | 是否必填 |
|---|---|---|
| 用户 ID | 账号的唯一标识 | 是 |
| 用户名 | 登录使用的用户名 | 是 |
| 邮箱 | 邮箱地址 | 是 |
| 手机号 | 手机号码 | 否 |
| 生日 | 生日信息 | 否 |
| 密码 | 登录密码(创建时必填) | 创建时必填 |
应用账号管理
应用账号用于服务间认证,包含以下信息:
| 字段 | 说明 | 是否必填 |
|---|---|---|
| 用户 ID | 账号的唯一标识 | 是 |
| 名称 | 账号名称 | 是 |
| 所属应用 | 关联的应用 | 是 |
| 描述 | 账号描述 | 否 |
账号详情
在账号详情页面可以查看:
- 基本信息:用户名、邮箱、手机号等
- 关联群组:该账号加入的所有群组
- 账号权限:该账号直接分配的权限(包括通过群组继承的权限)
- 登录历史:该账号的登录记录(仅个人账号)
- 凭证:该账号的 Access Key 列表(仅应用账号)
创建账号
- 进入「账号」页面
- 切换到「个人账号」或「应用账号」标签
- 点击「创建账号」
- 填写账号信息
- 点击「确认」创建
注意:创建应用账号后,可以在详情页面查看和管理 Access Key。
群组管理
群组是用户的集合,用于批量分配权限。
群组信息
| 字段 | 说明 |
|---|---|
| 群组名称 | 群组的唯一名称 |
| 描述 | 群组描述信息 |
| 创建时间 | 群组创建时间 |
| 更新时间 | 群组最后更新时间 |
群组详情
在群组详情页面可以查看:
- 基本信息:群组名称、描述等
- 群组成员:该群组包含的所有账号
- 群组权限:该群组拥有的权限
管理群组成员
- 进入群组详情
- 切换到「群组成员」标签
- 点击「添加成员」
- 选择要添加的账号
- 点击「确认」
移除成员:在成员列表中点击删除按钮即可。
管理群组权限
- 进入群组详情
- 切换到「群组权限」标签
- 点击「添加权限」
- 选择要添加的权限
- 点击「确认」
移除权限:在权限列表中点击删除按钮即可。
权限管理
权限是 API 接口的集合,表示一组操作能力。
权限信息
| 字段 | 说明 |
|---|---|
| 权限名称 | 权限的唯一名称 |
| 描述 | 权限描述信息 |
| 所属应用 | 权限所属的应用 |
| 接口数量 | 该权限包含的 API 数量 |
| 创建时间 | 权限创建时间 |
权限详情
在权限详情页面可以查看:
- 基本信息:权限名称、描述、所属应用等
- 关联接口:该权限包含的所有 API
- 授权账号:直接分配了该权限的账号(不包括通过群组继承的)
管理关联接口
- 进入权限详情
- 切换到「关联接口」标签
- 点击「添加接口」
- 选择要添加的 API
- 点击「确认」
移除接口:在接口列表中点击删除按钮即可。
应用管理
应用是权限管理的容器,每个应用都有自己的 API 和权限。
应用信息
| 字段 | 说明 |
|---|---|
| 应用 ID | 应用的唯一标识,创建时自动生成 |
| App Key | 应用的业务标识,展示在应用列表的「应用 ID」列 |
| 应用名称 | 应用名称 |
| 描述 | 应用描述信息 |
| 创建时间 | 应用创建时间 |
应用详情
在应用详情页面可以查看:
- 基本信息:应用 ID、名称、描述等
- 权限列表:该应用下创建的所有权限
- 接口列表:该应用下定义的所有 API
创建应用
- 进入「应用」页面
- 点击「创建应用」
- 填写应用名称和描述
- 点击「确认」创建
创建应用后,系统会自动生成应用 ID。
已知限制:当前版本服务端在创建应用时不会自动生成 App Key。若应用列表中该列为空,需要管理员通过数据库初始化或后续版本提供的配置入口写入。
租户管理
租户用于实现多租户隔离,每个租户拥有独立的数据空间。
租户信息
| 字段 | 说明 |
|---|---|
| 租户名称 | 租户名称 |
| 描述 | 租户描述信息 |
| 创建时间 | 租户创建时间 |
租户详情
在租户详情页面可以查看:
- 基本信息:租户名称、描述等
- 租户管理员:该租户的管理员账号列表
创建租户
注意:只有主租户(ID 为 1)的管理员才能创建新租户。
- 进入「租户」页面
- 点击「创建租户」
- 填写租户名称和描述
- 点击「确认」创建
创建租户成功后,系统会自动生成租户管理员账号的凭证信息,包括:
- 租户名称
- 用户 ID
- 密码
重要:租户管理员凭证只能下载一次,请妥善保存!
租户管理
多租户是当前 SaaS 云服务的关键特点之一,Passport 提供了完整的租户隔离能力。不同租户之间的数据完全隔离,互不影响。
超级租户
超级租户(ID 为 1)拥有系统最高权限,可以创建和管理其他租户。只有超级租户的管理员才能执行以下操作:
- 创建新租户
- 查看所有租户信息
- 管理跨租户配置
租户信息
每个租户包含以下信息:
| 字段 | 说明 |
|---|---|
| 租户名称 | 租户名称 |
| 描述 | 租户描述信息 |
| 创建时间 | 租户创建时间 |
创建租户
创建租户的操作只能在超级租户下进行。
创建步骤
- 登录超级租户管理后台
- 进入「租户」页面
- 点击「创建租户」
- 填写租户名称和描述
- 点击「确认」创建
创建租户管理员
租户创建完成后,系统会在该租户下自动创建一个租户管理员账号。创建成功后,系统会弹出提示:
租户创建成功。租户管理员凭证仅可下载一次,请妥善保存。
点击「下载」按钮即可获取租户管理员凭证信息,包括:
- 租户名称
- 用户 ID
- 密码
重要提醒:
- 凭证文件只能下载一次,请立即保存
- 建议将凭证信息存储在安全的地方
- 不要通过不安全的方式传输凭证
管理租户管理员
出于安全考虑,不建议多人使用同一个管理员账号。正确的操作方式是:
- 使用初始租户管理员账号登录
- 创建新的管理员账号
- 将新管理员账号添加到具有管理权限的群组
- 测试新账号权限正常后
- 删除或禁用初始租户管理员账号
查看租户详情
在租户列表中点击租户名称,可以进入租户详情页面查看:
- 基本信息:租户名称、描述等
- 租户管理员:该租户的所有管理员账号
提示:如果需要新增或移除租户管理员,请在群组中进行操作。
账号管理
Passport 基于统一的账号体系来进行身份识别和权限管控。账号体系是 Passport 最核心的部分,支撑起整个应用生态內的互联互通。

账号类型
系统支持两种类型的账号,分别对应不同的使用场景:
| 类型 | 说明 | 典型场景 |
|---|---|---|
| 个人账号 | 真人用户使用的账号 | 普通用户登录应用、员工使用企业系统 |
| 应用账号 | 服务之间调用的账号 | 微服务间 API 通信、服务认证 |
个人账号
个人账号用于真人用户登录系统,具有以下特点:
- 支持邮箱登录
- 需要密码验证
- 可以绑定到多个群组
- 可以分配多个权限
- 保留登录历史记录
应用账号
应用账号用于服务之间的 API 调用认证,具有以下特点:
- 通过 Access Key ID / Secret Access Key 认证
- 关联到具体的应用
- 用于服务间通信,无需人工登录
- 支持创建和管理多个凭证
- 不保留登录历史
账号列表
账号页面提供标签页切换功能,分别显示:
- 个人账号:所有个人账号列表
- 应用账号:所有应用账号列表
在账号列表中可以查看以下信息:
| 字段 | 说明 |
|---|---|
| 用户 ID | 账号的唯一标识 |
| 名称 | 用户名或应用账号名称 |
| 类型 | 账号类型(个人账号/应用账号) |
| 邮箱 | 邮箱地址(仅个人账号) |
| 所属应用 | 关联的应用(仅应用账号) |
| 上次登录时间 | 最近一次登录时间 |
| 创建时间 | 账号创建时间 |
创建个人账号
- 进入「账号」页面
- 切换到「个人账号」标签
- 点击「创建账号」
- 填写以下信息:
- 用户 ID(必填)
- 用户名(必填)
- 邮箱(必填)
- 密码(必填)
- 手机号(选填)
- 生日(选填)
- 点击「确认」创建
创建应用账号
- 进入「账号」页面
- 切换到「应用账号」标签
- 点击「创建账号」
- 填写以下信息:
- 用户 ID(必填)
- 名称(必填)
- 所属应用(必填)
- 描述(选填)
- 点击「确认」创建
账号详情
在账号列表中点击账号名称,可以进入账号详情页面。
个人账号详情
个人账号详情页面包含以下标签页:
| 标签页 | 内容 | 说明 |
|---|---|---|
| 基本信息卡 | 用户基本信息 | 显示用户名、邮箱、手机号等 |
| 关联群组 | 该账号加入的所有群组 | 可以添加或移除群组 |
| 账号权限 | 该账号的权限列表 | 只读,包括通过群组继承的权限 |
| 登录历史 | 登录记录 | 显示客户端 IP 和登录时间 |
应用账号详情
应用账号详情页面包含以下标签页:
| 标签页 | 内容 | 说明 |
|---|---|---|
| 基本信息卡 | 账号基本信息 | 显示名称、所属应用等 |
| 关联群组 | 该账号加入的所有群组 | 可以添加或移除群组 |
| 账号权限 | 该账号的权限列表 | 只读,包括通过群组继承的权限 |
| 凭证 | Access Key 列表 | 可以创建和管理凭证 |
| 登录历史 | 登录记录 | 显示客户端 IP 和登录时间 |
管理凭证
应用账号需要通过 Access Key 进行认证。
创建凭证
- 进入应用账号详情
- 切换到「凭证」标签
- 点击「创建凭证」
- 系统自动生成:
- Access Key ID
- Secret Access Key
- 点击「复制」保存凭证信息
重要:Secret Access Key 只在创建时显示一次,请立即保存!
删除凭证
- 进入应用账号详情
- 切换到「凭证」标签
- 找到要删除的凭证
- 点击删除按钮
- 确认删除
注意:删除凭证后,使用该凭证的 API 调用将立即失败。
关联群组
将账号加入群组可以快速获得群组的权限。
添加到群组
- 进入账号详情
- 切换到「关联群组」标签
- 点击「添加群组」
- 选择要加入的群组
- 点击「确认」
从群组移除
- 进入账号详情
- 切换到「关联群组」标签
- 找到要移除的群组
- 点击删除按钮
- 确认移除
查看账号权限
账号权限标签页显示该账号拥有的所有权限,包括:
- 直接分配给该账号的权限
- 通过群组继承的权限
权限列表为只读,如需修改权限,请通过群组管理页面操作。
群组管理
为了降低账号管理难度,Passport 提供了账号分组能力。在企业组织中,管理员可以将相同岗位的用户账号加入到同一个群组中,只需要针对群组进行授权,群组中所有账号就可以获得相同的权限,无需单独为每个账号分别授权。

群组概述
群组是账号的集合,用于批量管理权限。通过群组,管理员可以:
- 快速为多个账号分配相同的权限
- 简化权限管理流程
- 提高权限变更效率
群组信息
每个群组包含以下信息:
| 字段 | 说明 |
|---|---|
| 群组名称 | 群组的唯一名称 |
| 描述 | 群组描述信息 |
| 创建时间 | 群组创建时间 |
| 更新时间 | 群组最后更新时间 |
创建群组
- 进入「群组」页面
- 点击「创建群组」
- 填写以下信息:
- 群组名称(必填)
- 描述(选填)
- 点击「确认」创建
群组详情
在群组列表中点击群组名称,可以进入群组详情页面。群组详情包含以下标签页:
| 标签页 | 内容 | 说明 |
|---|---|---|
| 基本信息卡 | 群组基本信息 | 显示群组名称、描述等 |
| 群组成员 | 该群组包含的所有账号 | 可以添加或移除成员 |
| 群组权限 | 该群组拥有的权限 | 可以添加或移除权限 |
管理群组成员
将账号添加到群组后,该账号会自动获得群组的所有权限。
添加成员
- 进入群组详情
- 切换到「群组成员」标签
- 点击「添加成员」
- 选择要添加的账号(支持多选)
- 点击「确认」
移除成员
- 进入群组详情
- 切换到「群组成员」标签
- 找到要移除的账号
- 点击删除按钮
- 确认移除
注意:移除成员后,该账号将失去群组的所有权限。
管理群组权限
为群组添加权限后,群组中的所有账号都会获得这些权限。
添加权限
- 进入群组详情
- 切换到「群组权限」标签
- 点击「添加权限」
- 选择要添加的权限(支持多选)
- 点击「确认」
移除权限
- 进入群组详情
- 切换到「群组权限」标签
- 找到要移除的权限
- 点击删除按钮
- 确认移除
注意:移除权限后,群组中的所有账号都会失去该权限。
权限继承
群组的权限会自动继承给群组中的所有账号。当群组权限发生变化时:
- 添加权限:群组中所有账号立即获得新权限
- 移除权限:群组中所有账号立即失去该权限
账号的实际权限是以下权限的并集:
- 直接分配给账号的权限
- 账号所属群组的权限
群组使用建议
按部门/组织架构分组
- 开发部群组
- 产品部群组
- 运营部群组
- ...
按岗位角色分组
- 管理员群组
- 操作员群组
- 只读用户群组
- ...
按项目分组
- 项目 A 群组
- 项目 B 群组
- ...
注意事项
- 一个账号可以加入多个群组
- 群组权限变化会立即生效
- 建议定期审查群组成员和权限配置
- 不再使用的群组建议删除或禁用
权限管理
权限是 API 接口的集合,表示一组操作能力。用户想要正常使用某个服务,必须先拥有该服务的相应权限。

权限概述
权限是连接账号和 API 的桥梁。通过权限,管理员可以:
- 将多个 API 组合成一个权限单元
- 将权限分配给账号或群组
- 实现细粒度的访问控制
一般服务至少会定义三个级别的权限:
| 权限级别 | 风险等级 | 对应角色 | 描述 |
|---|---|---|---|
| 管理员权限 | 高风险 | 管理员 | 拥有系统的所有操作权限 |
| 操作者权限 | 中风险 | 操作者 | 拥有大部分操作权限,但无法进行系统配置 |
| 只读权限 | 低风险 | 只读用户 | 仅拥有查询权限 |
权限信息
每个权限包含以下信息:
| 字段 | 说明 |
|---|---|
| 权限名称 | 权限的唯一名称 |
| 描述 | 权限描述信息 |
| 所属应用 | 权限所属的应用 |
| 接口数量 | 该权限包含的 API 数量 |
| 创建时间 | 权限创建时间 |
权限列表
在权限列表中可以查看所有已创建的权限,包括:
| 字段 | 说明 |
|---|---|
| 权限名称 | 点击可进入详情页 |
| 所属应用 | 权限所属的应用名称 |
| 接口数量 | 该权限包含的 API 数量 |
| 创建时间 | 权限创建时间 |
创建权限
- 进入「权限」页面
- 点击「创建权限」
- 填写以下信息:
- 权限名称(必填)
- 所属应用(必填,从下拉列表选择)
- 描述(选填)
- 点击「确认」创建
创建权限后,可以在权限详情中添加关联的 API。
权限详情
在权限列表中点击权限名称,可以进入权限详情页面。权限详情包含以下标签页:
| 标签页 | 内容 | 说明 |
|---|---|---|
| 基本信息卡 | 权限基本信息 | 显示权限名称、描述、所属应用等 |
| 关联接口 | 该权限包含的所有 API | 可以添加或移除接口 |
| 授权账号 | 直接分配了该权限的账号 | 只读,不包括通过群组继承的 |
管理关联接口
将 API 添加到权限后,拥有该权限的账号/群组就可以访问这些 API。
添加接口
- 进入权限详情
- 切换到「关联接口」标签
- 点击「添加接口」
- 选择要添加的 API(支持多选)
- 点击「确认」
移除接口
- 进入权限详情
- 切换到「关联接口」标签
- 找到要移除的 API
- 点击删除按钮
- 确认移除
注意:移除接口后,拥有该权限的账号将无法访问该接口。
查看授权账号
授权账号标签页显示直接分配了该权限的所有账号。
注意:此列表只显示直接分配了权限的账号,不包括通过群组继承获得权限的账号。如需查看所有拥有该权限的账号,请分别查看每个群组的成员列表。
权限设计建议
按功能模块划分
- 用户管理权限
- 产品管理权限
- 订单管理权限
- ...
按操作类型划分
- 查看权限
- 编辑权限
- 删除权限
- ...
按风险等级划分
- 管理员权限(高风险)
- 操作者权限(中风险)
- 只读权限(低风险)
组合方式
实际应用中,通常会采用组合方式,例如:
| 权限名称 | 描述 | 包含 API |
|---|---|---|
| user-admin | 用户管理(管理员) | 用户查询、创建、编辑、删除的所有 API |
| user-operator | 用户管理(操作者) | 用户查询、创建、编辑的 API |
| user-reader | 用户管理(只读) | 仅用户查询 API |
注意事项
- 权限名称应具有描述性,便于识别
- 建议为每个应用至少创建三个权限级别
- 定期审查权限配置,确保安全性
- 避免创建过于细碎的权限,增加管理复杂度
应用管理
应用是权限管理的容器,每个应用都有自己的 API 和权限。应用管理允许开发者在 Passport 平台上注册自己的应用,并定义应用的 API 接口清单和权限体系。

应用概述
应用是指需要接入 Passport 认证鉴权的业务系统或服务。每个应用在 Passport 中都有独立的:
- 应用 ID(App Key):应用的唯一标识
- API 列表:应用暴露的所有接口
- 权限列表:应用定义的权限
- 应用账号:用于服务间调用的账号
应用信息
每个应用包含以下信息:
| 字段 | 说明 |
|---|---|
| 应用 ID(App Key) | 应用的唯一标识,创建时自动生成 |
| 应用名称 | 应用名称 |
| 描述 | 应用描述信息 |
| 创建时间 | 应用创建时间 |
应用列表
在应用列表中可以查看所有已注册的应用:
| 字段 | 说明 |
|---|---|
| 应用 ID | 点击可进入详情页 |
| 应用名称 | 应用名称 |
| 描述 | 应用描述信息 |
| 创建时间 | 应用创建时间 |
创建应用
- 进入「应用」页面
- 点击「创建应用」
- 填写以下信息:
- 应用名称(必填)
- 描述(选填)
- 点击「确认」创建
创建应用成功后,系统会自动生成应用 ID(App Key),用于唯一标识该应用。
应用详情
在应用列表中点击应用 ID,可以进入应用详情页面。应用详情包含以下标签页:
| 标签页 | 内容 | 说明 |
|---|---|---|
| 基本信息卡 | 应用基本信息 | 显示应用 ID、名称、描述等 |
| 权限 | 该应用下创建的所有权限 | 只读,列出权限名称和接口数量 |
| 接口 | 该应用下定义的所有 API | 可以添加、编辑、删除接口 |
管理接口
接口是权限控制的基本单位,每个接口代表一个具体的 API 端点。
创建接口
- 进入应用详情
- 切换到「接口」标签
- 点击「创建接口」
- 填写以下信息:
- 接口名称(必填)
- 请求路径(必填)
- 请求方法(必填,支持 GET/POST/PUT/DELETE)
- 描述(选填)
- 点击「确认」创建
编辑接口
- 进入应用详情
- 切换到「接口」标签
- 找到要编辑的接口
- 点击编辑按钮
- 修改接口信息
- 点击「确认」保存
删除接口
- 进入应用详情
- 切换到「接口」标签
- 找到要删除的接口
- 点击删除按钮
- 确认删除
注意:删除接口后,该接口将从所有关联的权限中移除。
导出接口列表
应用管理支持导出接口列表,方便在开发过程中使用。
- 进入应用详情
- 切换到「接口」标签
- 点击「导出」按钮
- 选择导出格式
- 保存导出文件
接口信息
每个接口包含以下信息:
| 字段 | 说明 |
|---|---|
| 接口名称 | 接口的名称 |
| 请求路径 | 接口的请求路径,支持通配符(如 /api/user/*) |
| 请求方法 | HTTP 方法(GET/POST/PUT/DELETE) |
| 描述 | 接口描述信息 |
| 更新时间 | 接口最后更新时间 |
接口路径匹配规则
Passport SDK 支持灵活的接口路径匹配规则:
| 路径模式 | 说明 | 匹配示例 |
|---|---|---|
/api/user | 精确匹配 | /api/user |
/api/user/* | 前缀匹配 | /api/user/1, /api/user/info |
/api/user/{id} | 路径变量匹配 | /api/user/123, /api/user/abc |
创建应用账号
应用需要账号来进行服务间认证。
创建应用账号
- 进入「账号」页面
- 切换到「应用账号」标签
- 点击「创建账号」
- 填写以下信息:
- 用户 ID(必填)
- 名称(必填)
- 所属应用(必填,选择该应用)
- 描述(选填)
- 点击「确认」创建
管理凭证
创建应用账号后,需要创建 Access Key 凭证:
- 进入应用账号详情
- 切换到「凭证」标签
- 点击「创建凭证」
- 保存生成的 Access Key ID 和 Secret Access Key
应用集成流程
完成应用注册后,按照以下步骤集成 Passport:
- 创建应用:在管理后台创建应用,获取应用 ID
- 定义接口:将应用的 API 接口清单注册到应用中
- 创建权限:定义应用的权限级别(管理员、操作者、只读等)
- 关联接口:将接口关联到对应的权限
- 创建应用账号:创建应用服务账号,获取 Access Key
- 引入 SDK:在应用代码中引入 Passport SDK
- 配置 SDK:配置应用 ID、Access Key、公钥等信息
- 测试验证:测试认证鉴权功能是否正常
详细的 SDK 集成步骤请参考 Passport SDK 集成。
注意事项
- 应用 ID(App Key)是应用的重要标识,请妥善保存
- 接口路径的匹配规则与 Spring Boot 的路径匹配规则一致
- 建议按照功能模块组织接口和权限
- 定期审查接口和权限配置,确保安全性
服务发布与接入
本章节主要面向服务责任人和接入认证鉴权功能的开发人员。
为了集成 Passport 提供的认证鉴权能力,需要完成以下两个主要步骤:
-
服务发布
-
Passport SDK 集成
接入方式概览
| 接入方式 | 说明 | 适用场景 |
|---|---|---|
| Java SDK | 提供 Spring Boot 自动配置,开箱即用 | Java Spring Boot 应用 |
| Go SDK | 提供 Gin 中间件,简化集成 | Go Gin 框架应用 |
| 公开 API | 直接调用 REST API | 任意语言或框架 |
服务发布
服务发布是指在 Passport 平台上注册应用,定义 API 接口和权限,为后续接入做准备。
具体步骤
1. 创建应用
- 登录 Passport 管理后台
- 进入「应用」页面
- 点击「创建应用」

- 填写应用信息:
- 应用名称(必填)
- 描述(选填)
- 点击「确认」创建
创建成功后,系统会自动生成应用 ID,用于唯一标识该应用。
已知限制:当前版本服务端在创建应用时不会自动生成 App Key,该字段需要另行配置。详见「高阶操作」的应用管理章节。
2. 创建应用账号
应用需要账号来进行服务间认证(如调用 Passport 公开接口)。
- 进入「账号」页面
- 切换到「应用账号」标签
- 点击「创建账号」
- 填写以下信息:
- 用户 ID(必填)
- 名称(必填)
- 所属应用(必填,选择刚创建的应用)
- 描述(选填)
- 点击「确认」创建
3. 获取 Access Key
应用账号创建后,需要获取凭证用于 API 调用。
- 进入应用账号详情
- 切换到「凭证」标签
- 点击「创建凭证」
- 系统自动生成:
- Access Key ID
- Secret Access Key
- 保存凭证信息
重要:Secret Access Key 只在创建时显示一次,请立即保存!
4. 定义 API 接口
将应用的 API 接口清单注册到 Passport 平台。
- 进入应用详情
- 切换到「接口」标签
- 点击「创建接口」
- 填写接口信息:
- 接口名称(必填)
- 请求路径(必填,如
/api/user/*) - 请求方法(必填,支持 GET/POST/PUT/DELETE)
- 描述(选填)
- 点击「确认」创建
重复以上步骤,将所有接口注册到平台。
5. 导出接口列表
应用管理支持导出接口列表,方便在开发过程中使用。
- 进入应用详情
- 切换到「接口」标签
- 点击「导出」按钮
- 保存导出的文件
导出结果为 Excel 文件(.xlsx),文件名格式为 API-yyyyMMddHHmmss.xlsx,例如 API-20260830143022.xlsx。当前仅支持这一种格式。
6. 创建权限
定义应用的权限级别。
- 进入「权限」页面
- 点击「创建权限」
- 填写以下信息:
- 权限名称(必填)
- 所属应用(必填,选择刚创建的应用)
- 描述(选填)
- 点击「确认」创建
建议为每个应用创建至少三个权限级别:
| 权限级别 | 风险等级 | 对应角色 | 描述 |
|---|---|---|---|
| 管理员权限 | 高风险 | 管理员 | 拥有应用的所有操作权限 |
| 操作者权限 | 中风险 | 操作者 | 拥有大部分操作权限 |
| 只读权限 | 低风险 | 只读用户 | 仅拥有查询权限 |
7. 关联接口到权限
将 API 接口关联到对应的权限。
- 进入权限详情
- 切换到「关联接口」标签
- 点击「添加接口」
- 选择要添加的 API(支持多选)
- 点击「确认」
重复以上步骤,将所有接口关联到对应的权限。
信息汇总
完成服务发布后,您将获得以下信息:
| 信息 | 说明 | 获取方式 |
|---|---|---|
| 应用 ID | 应用的唯一标识 | 应用详情页 |
| Access Key ID | 应用账号的访问密钥 ID | 凭证列表 |
| Secret Access Key | 应用账号的密钥 | 创建凭证时(仅显示一次) |
| 接口清单 | 所有已注册的 API | 应用详情页 > 接口标签 |
| 权限清单 | 所有已创建的权限 | 权限列表页 |
| API-权限映射 | 接口与权限的关联关系 | 权限详情页 > 关联接口标签 |
这些信息将在 SDK 集成和 API 调用时使用。
SDK 集成(Java)
Passport SDK 基于 Cookie 共享机制实现,受跨域限制,因此主要适用于为同域站点提供认证鉴权。其意义主要在于简化应用后台认证鉴权流程的实现,只需要引入依赖包就可以一步到位完成接口拦截。

Passport SDK 当前提供 Java 和 Go 版本:
- Java SDK:适用于 Spring Boot 框架的应用
- Go SDK:适用于 Gin 框架的应用
工作原理
SDK 通过以下机制实现认证鉴权:
- 认证拦截:通过
AuthFilter拦截所有请求,验证 Token 有效性 - Token 验证:使用公钥验证 JWT Token 签名,解析用户信息
- 权限控制:从本地缓存的 API 和权限配置中,验证用户是否有访问权限
- 缓存同步:通过定时任务从 Passport 服务同步 API 和权限配置
Step 1:引入 Maven 依赖
<dependency>
<groupId>com.vancone</groupId>
<artifactId>vancone-passport-sdk</artifactId>
<version>0.1.4</version>
</dependency>
依赖说明
SDK 依赖以下组件:
- Spring Boot Starter Web - Web 应用基础
- Spring Boot Starter AOP - 面向切面编程支持
- JJWT - JWT Token 解析
- Spring Security Crypto - 加解密支持
- vancone-web-common - VanCone Web 通用组件
SDK 不需要 Redis。API 与权限配置缓存在应用进程的内存中,由定时任务刷新,接入方无需额外准备缓存中间件。
Step 2:修改配置文件
# ====================================
# Passport SDK 配置
# ====================================
# Passport 平台部署的地址,用于登录跳转和同步鉴权信息
passport.base-url=https://passport.vancone.com
# 应用账号的 Access Key ID(在 Passport 管理后台创建应用时生成)
passport.app-account.access-key-id=AKIDxxxxxxxxxxxxxxxxxx
# 应用账号的 Secret Access Key
passport.app-account.secret-access-key=xxxxxxxxxxxxxxxxxx
# Token 验证所需的公钥(Base64 编码)
passport.token.public-key=MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXxxxxxxxxxxxxxxxxxx
# Token 算法类型,当前仅支持 ES256
passport.token.algorithm=ES256
# 是否启用权限控制,false 表示只进行认证不进行鉴权
passport.access-control.enabled=true
# 本地缓存同步周期(秒),用于从 Passport 服务同步 API 和权限配置
passport.cache.sync-period-seconds=60
# 不需要认证的 URI 前缀列表(逗号分隔),如公开接口、健康检查等
passport.permitUriPrefix=/public,/health,/actuator
配置说明
| 配置项 | 必填 | 默认值 | 说明 |
|---|---|---|---|
passport.base-url | 是 | https://passport.vancone.com | Passport 服务地址 |
passport.app-account.access-key-id | 是 | - | 应用账号 Access Key ID |
passport.app-account.secret-access-key | 是 | - | 应用账号 Secret Access Key |
passport.token.public-key | 是 | - | 用于验证 Token 的公钥(Base64) |
passport.token.algorithm | 否 | ES256 | Token 签名算法,当前仅支持 ES256 |
passport.access-control.enabled | 否 | true | 是否启用权限控制 |
passport.cache.sync-period-seconds | 否 | 60 | 缓存同步周期(秒) |
passport.permitUriPrefix | 否 | - | 不需要认证的 URI 前缀 |
Step 3:设置启动类的组件扫描范围
@SpringBootApplication
@ComponentScan(basePackages = "com.vancone")
public class PassportClientApplication {
public static void main(String[] args) {
SpringApplication.run(PassportClientApplication.class, args);
}
}
注意:SDK 使用 Spring Boot 的自动配置机制,通过 spring.factories 自动注册组件。但需要确保 com.vancone 包在组件扫描范围内,否则无法加载 SDK 的 Bean。
在代码中获取当前用户信息
SDK 将解析后的用户信息存储在 ThreadLocal 中,可以在业务代码中通过 TokenUtil 获取:
import com.vancone.passport.sdk.util.TokenUtil;
import com.vancone.passport.sdk.entity.AccountInfo;
public class MyController {
@GetMapping("/api/user/info")
public Response getUserInfo() {
// 获取当前登录用户的账户信息
AccountInfo accountInfo = TokenUtil.getAccountInfo();
if (accountInfo != null) {
// 获取用户 ID
String userId = accountInfo.getUserId();
// 获取账户 ID
String accountId = accountInfo.getId();
// 获取租户 ID
String tenantId = accountInfo.getTenantId();
// 获取权限 ID 列表
List<Long> permissionIds = accountInfo.getPermissionIds();
return Response.success(accountInfo);
}
return Response.fail(401, "Not logged in");
}
}
AccountInfo 属性
| 属性 | 类型 | 说明 |
|---|---|---|
id | String | 账户 ID |
userId | String | 用户 ID |
name | String | 用户名称 |
type | String | 账户类型 |
tenantId | String | 租户 ID |
permissionIds | List | 权限 ID 列表 |
认证流程说明
-
请求到达:客户端发起请求,SDK 的
AuthFilter拦截请求 -
Token 获取:SDK 按以下顺序获取 Token:
- 从 HTTP Header
passport-token获取 - 从 Cookie
passport_token获取
- 从 HTTP Header
-
Token 验证:使用配置的公钥验证 Token 签名
-
权限验证(如果启用):
- 从 Token 中提取用户的权限 ID 列表
- 从本地缓存中匹配请求的 API
- 验证用户权限是否包含该 API
-
请求处理:验证通过后,将用户信息存入
ThreadLocal,继续处理请求 -
清理:请求结束后,自动清理
ThreadLocal中的用户信息
响应状态码
SDK 在认证鉴权失败时返回以下状态码:
| 状态码 | 说明 | 响应体 |
|---|---|---|
| 401 | 未登录或 Token 无效 | {"code": 401, "message": "Login required", "data": "https://passport.vancone.com"} |
| 403 | 无权限访问 | {"code": 403, "message": "No permission"} |
前端可以检查 401 响应中的 data 字段,获取登录地址进行跳转。
获取公钥
管理后台当前不提供公钥查询页面。 公钥需要从 Passport 服务端的配置文件(
passport.token.public-key)中获取,请向 Passport 的部署运维人员索取。
公钥为 Base64 编码的 PKIX 公钥(与私钥 passport.token.private-key 成对生成,服务端使用 ES256 签名)。
如果需要自行生成密钥对,可使用 OpenSSL:
# 生成 ES256(prime256v1)密钥对
openssl ecparam -genkey -name prime256v1 -noout -out private.pem
openssl ec -in private.pem -pubout -out public.pem
# 提取 PKIX 公钥的 Base64 正文(去掉头尾与换行)
grep -v "^-" public.pem | tr -d '\n'
将上一步输出的 Base64 字符串填入 passport.token.public-key。
服务端的
public-key与private-key必须成对替换,否则已签发的 Token 将全部校验失败。
缓存同步机制
SDK 通过 SyncScheduler 定时从 Passport 服务同步数据,缓存在应用进程内存中(不依赖 Redis 等外部缓存):
| 缓存数据 | 同步接口 | 说明 |
|---|---|---|
| API 配置 | /api/passport/service/v1/sync/api | 同步服务的 API 路径和方法定义 |
| 权限配置 | /api/passport/service/v1/sync/permission | 同步权限与 API 的关联关系 |
同步周期由 passport.cache.sync-period-seconds 配置控制,默认 60 秒。
创建应用账号
在 Passport 管理后台创建应用账号,获取 Access Key:
- 登录 Passport 管理后台
- 进入「应用管理」
- 创建新应用或选择现有应用
- 查看应用的 Access Key ID 和 Secret Access Key
常见问题
Q: Token 从哪里获取?
A: 用户在 Passport 平台登录后,Token 会以以下方式存储:
- Cookie:
passport_token - Header:
passport-token
前端可以将 Token 设置到后续请求的 Header 中,也可以依赖 Cookie 自动传递。
Q: 如何调试 Token 验证问题?
A: SDK 会输出详细日志,可以通过以下方式调试:
# 启用 SDK 日志
logging.level.com.vancone.passport.sdk=DEBUG
Q: 支持哪些加密算法?
A: 仅支持 ES256(ECDSA using P-256 curve)。Passport 服务端签发 Token 时固定使用 ES256,passport.token.algorithm 配置仅用于校验端保持一致,填写其他算法会导致所有 Token 校验失败。
SDK 集成(Go)
Passport Go SDK 基于 Gin 框架设计,提供中间件和工具函数,帮助 Go 应用快速集成 Passport 的认证鉴权功能。
版本说明(重要)
本章基于
github.com/vancone/vancone-passport-sdk-go的develop分支(e7e27d0,2026-02-08)。该仓库当前尚未发布与本章 API 对应的正式版本:
- 默认分支
main仍停留在初始提交,不包含 SDK 代码。- 已发布的 tag
v0.1.0.20250805.1(2025-08-05)是早期版本,其 API 与本章不兼容(入口函数、包路径、配置键名均不同)。因此请勿使用不带版本约束的
go get,请按 Step 1 显式指定develop分支,或等待正式版本发布后按发版说明锁定版本号。
快速开始
Step 1:安装 SDK
go get github.com/vancone/vancone-passport-sdk-go@develop
SDK 的间接依赖(无需手动引入):github.com/gin-gonic/gin、github.com/spf13/viper、github.com/golang-jwt/jwt/v5。要求 Go 1.21.3 及以上。
Step 2:修改配置文件
在 config.yaml 或 config.yml 中添加以下配置:
passport:
# 平台配置
platform:
base-url: https://passport.vancone.com # Passport 平台地址
# Token 配置
token:
public-key: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE... # Base64 编码的公钥
# 认证配置
authentication:
enabled: true # 是否开启登录认证
uri-allowlist: # 不需要登录认证的 URI 列表
- /api/v1/public/**
- /health
# 应用账号配置(仅在调用 Passport 接口时需要)
app-account:
ak: AKIDxxxxxxxxxxxxxxxx # Access Key ID
sk: xxxxxxxxxxxxxxxxxxx # Secret Access Key
配置说明:
| 配置项 | 必填 | 默认值 | 说明 |
|---|---|---|---|
platform.base-url | 否 | https://passport.vancone.com | Passport 平台地址,SDK 调用平台接口时的前缀 |
token.public-key | 是 | - | 用于校验 Token 的公钥(Base64 编码的 PKIX 公钥) |
authentication.enabled | 否 | true | 是否开启登录认证;置为 false 时中间件直接放行所有请求 |
authentication.uri-allowlist | 否 | - | 不需要登录认证的 URI 模式列表,支持路径模式匹配(见「路径模式」) |
app-account.ak | 否 | - | 应用账号的 Access Key ID,仅在调用 ApplyToken / RequestWithAuth / Request(auth=true) 时需要 |
app-account.sk | 否 | - | 应用账号的 Secret Access Key,同上 |
当前版本未生效的配置项(配置结构体中存在,但实现尚未使用,配置后不会产生任何效果):
| 配置项 | 状态 |
|---|---|
platform.cache-sync-seconds | 预留字段。Token 缓存周期固定为 3600 秒,不可配置 |
token.algorithm | 预留字段。SDK 仅支持 ES256,非 ECDSA 签名的 Token 一律校验失败 |
access-control.enabled | 预留字段。权限校验尚未实现,见「权限校验」 |
access-control.uri-allowlist | 同上 |
csrf.enabled / csrf.secret-key | 预留字段,尚未实现 |
Step 3:初始化 SDK
package main
import (
"github.com/gin-gonic/gin"
"github.com/spf13/viper"
"github.com/vancone/vancone-passport-sdk-go/pkg/config"
"github.com/vancone/vancone-passport-sdk-go/pkg/middleware"
)
func main() {
// 读取配置
viper.SetConfigFile("config.yaml")
if err := viper.ReadInConfig(); err != nil {
panic(err)
}
// 初始化 SDK(必须在注册中间件之前调用)
config.Init(viper.GetViper())
r := gin.Default()
// 添加认证中间件
r.Use(middleware.AuthMiddleware)
r.Run(":8080")
}
注意:
AuthMiddleware位于pkg/middleware包,而不是pkg/config包。pkg/config只负责配置读取,不导出任何中间件。
Step 4:使用 SDK 工具
获取当前用户信息
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/vancone/vancone-passport-sdk-go/pkg/util"
)
func GetUser(ctx *gin.Context) {
// 获取完整的账号信息
accountInfo := util.GetAccountInfo(ctx)
if accountInfo != nil {
fmt.Printf("AccountId: %s\n", accountInfo.AccountId)
fmt.Printf("TenantId: %s\n", accountInfo.TenantId)
fmt.Printf("UserId: %s\n", accountInfo.UserId)
}
// 获取单个信息
tenantId := util.GetTenantId(ctx)
accountId := util.GetAccountId(ctx)
userId := util.GetUserId(ctx)
fmt.Println(tenantId, accountId, userId)
}
AccountInfo 结构体定义:
| 字段 | 类型 | 说明 |
|---|---|---|
tenantId | string | 租户 ID |
accountId | string | 账号 ID |
userId | string | 用户 ID(登录名) |
permissionIds | []string | 权限 ID 列表。当前版本不会填充该字段,值恒为空 |
若需要权限信息,请通过 Passport 开放接口自行查询,不要依赖
permissionIds字段。
获取应用账号 Token
import (
"github.com/vancone/vancone-passport-sdk-go/pkg/util"
)
func GetAppToken() string {
// 自动获取或刷新应用账号 Token(内部缓存 3600 秒)
token := util.ApplyToken()
return token
}
ApplyToken 使用 app-account.ak / app-account.sk 向 Passport 平台换取 Token,流程为:
POST {base-url}/api/passport/service/v1/token/signature,请求体{"accessKeyId": "...", "secretAccessKey": "..."},返回{"timestamp": "...", "signature": "..."}POST {base-url}/api/passport/service/v1/token,请求体{"accessKeyId": "...", "timestamp": "...", "signature": "..."},返回 Token 字符串
风险提示:若
ak/sk配置错误或应用账号无权限,平台返回的data为null,此时ApplyToken会抛出 panic。请确保在生产环境中正确配置ak/sk,并对调用方做好恢复处理。
发起认证请求
import (
"github.com/vancone/vancone-passport-sdk-go/pkg/util"
)
func CallPassportAPI() {
// 使用 SDK 的 HTTP 工具发送请求(自动携带应用账号 Token)
resp := util.Request("https://passport.vancone.com/api/passport/service/v1/account", "GET", "", true)
fmt.Println(string(resp))
// 等价于 Request(uri, method, body, true)
resp2 := util.RequestWithAuth("https://passport.vancone.com/api/passport/service/v1/account", "GET", "")
fmt.Println(string(resp2))
}
HTTP 工具函数:
| 函数 | 说明 |
|---|---|
util.Request(uri, method, body string, auth bool) []byte | 发起 HTTP 请求。auth 为 true 时自动在 passport-token 请求头中携带 ApplyToken() 获取的 Token。出错时返回 nil |
util.RequestWithAuth(uri, method, body string) []byte | 等价于 Request(uri, method, body, true) |
中间件说明
middleware.AuthMiddleware 的处理流程:
- 开关判断:若
authentication.enabled为false,直接放行所有请求。 - 白名单匹配:请求路径命中
authentication.uri-allowlist中的任一模式时放行,不做 Token 校验。 - 读取 Token:优先从 Cookie
passport_token读取;Cookie 为空时,从请求头passport-token读取。 - 校验 Token:使用配置中的公钥校验 ES256 签名,并校验有效期。
- 注入用户信息:校验通过后,将账号信息写入 Gin Context;校验失败则中断请求并返回 HTTP 401。
Token 的传递方式(前后端对接时需要对齐):
| 位置 | 名称 |
|---|---|
| Cookie | passport_token |
| 请求头 | passport-token |
鉴权失败的响应:当前版本中间件调用
AbortWithStatus(401)中断请求,响应体为空。如需与平台统一的错误格式({"code": 11002, "message": "Not authorized"})保持一致,请在业务侧自行追加一个错误处理中间件构造响应体。
Context 中可用的信息
通过中间件后,可以在 Handler 中通过 Gin Context 获取以下信息:
| Key 常量 | Key 实际值 | 类型 | 说明 |
|---|---|---|---|
constant.TokenKeyAccountId | acid | string | 账号 ID |
constant.TokenKeyTenantId | tid | string | 租户 ID |
constant.TokenKeyUserId | uid | string | 用户 ID(登录名) |
constant.AccountInfo | accountInfo | model.AccountInfo(值类型,非指针) | 完整账号信息 |
推荐通过 util.GetAccountInfo / util.GetTenantId 等工具函数读取,避免直接断言类型。若确实需要直接读取:
accountInfo := ctx.MustGet(constant.AccountInfo).(model.AccountInfo) // 注意是值类型
路径模式
authentication.uri-allowlist 支持以下三种模式:
| 路径模式 | 说明 | 优先级 |
|---|---|---|
/users/{id} | 精确匹配,支持路径变量 | 高 |
/users/* | 单段通配,匹配一层路径 | 中 |
/api/** | 多段通配,匹配任意层级(含零层) | 低 |
SDK 会按优先级从高到低排序,自动匹配最佳模式。匹配前会对模式与请求路径做规范化处理(合并重复斜杠、补全前导斜杠、去除末尾斜杠)。
权限校验
当前版本尚未实现。
access-control相关配置(见 Step 2)在配置结构体中存在,但中间件不会读取,配置后不会生效。
如需进行权限校验,请通过 Passport 开放接口在业务侧自行实现。SDK 提供的路径模式匹配能力(pkg/util/path_parser.go)可用于白名单场景。
示例:完整的用户控制器
package controller
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/vancone/vancone-passport-sdk-go/pkg/constant"
"github.com/vancone/vancone-passport-sdk-go/pkg/model"
"github.com/vancone/vancone-passport-sdk-go/pkg/util"
)
type UserController struct{}
// GetUser 获取当前用户信息
func (c *UserController) GetUser(ctx *gin.Context) {
accountInfo := util.GetAccountInfo(ctx)
if accountInfo == nil {
ctx.JSON(http.StatusUnauthorized, gin.H{"message": "Not authorized"})
return
}
ctx.JSON(http.StatusOK, gin.H{
"accountId": accountInfo.AccountId,
"userId": accountInfo.UserId,
"tenantId": accountInfo.TenantId,
})
}
// GetCurrentUserProfile 调用 Passport 平台获取用户资料
func (c *UserController) GetCurrentUserProfile(ctx *gin.Context) {
resp := util.RequestWithAuth(
"https://passport.vancone.com/api/passport/service/v1/account-profile", "GET", "")
ctx.Data(http.StatusOK, "application/json", resp)
}
// ReadRawAccountInfo 直接读取 Context(不推荐,注意是值类型)
func (c *UserController) ReadRawAccountInfo(ctx *gin.Context) {
accountInfo := ctx.MustGet(constant.AccountInfo).(model.AccountInfo)
ctx.JSON(http.StatusOK, accountInfo)
}
配置示例
最小配置(仅认证)
passport:
token:
public-key: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
完整配置(认证 + 平台调用)
passport:
platform:
base-url: https://passport.vancone.com
token:
public-key: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
app-account:
ak: AKIDxxxxxxxxxxxxxxxx
sk: xxxxxxxxxxxxxxxxxxx
authentication:
enabled: true
uri-allowlist:
- /api/v1/public/**
- /health
注意事项
- 公钥获取:公钥为 Base64 编码的 PKIX 公钥(ES256)。请从 Passport 部署方获取,并妥善保管;公钥变更会导致所有 Token 校验失败。
- 安装版本:务必指定
@develop或正式版本号,不带版本约束的go get会安装到 API 不兼容的旧版本。 - 初始化顺序:
config.Init()必须在注册middleware.AuthMiddleware之前调用,否则公钥与白名单均无法加载。 - URI 白名单:不需要认证的接口(如健康检查、公开查询)应添加到
authentication.uri-allowlist。 - 算法支持:当前版本仅支持 ES256,非 ECDSA 签名的 Token 会被直接拒绝。
- 权限校验:尚未实现,不要在业务中依赖
access-control配置或PermissionIds字段。
SDK 架构说明
| 模块 | 文件路径 | 说明 |
|---|---|---|
| 配置管理 | pkg/config/config.go | 使用 Viper 读取配置,提供默认值 |
| 中间件 | pkg/middleware/middleware.go | Token 验证、用户信息注入、URI 白名单 |
| Token 工具 | pkg/util/token.go | 应用账号 Token 申请与缓存、Token 校验、解析账号信息 |
| HTTP 工具 | pkg/util/http_util.go | 发起 HTTP 请求,可选自动携带 Token |
| 路径解析 | pkg/util/path_parser.go | 路径模式匹配 |
| 账号工具 | pkg/util/account_util.go | 从 Context 获取用户信息 |
| 模型定义 | pkg/model/account_info.go | AccountInfo 结构体 |
| 常量定义 | pkg/constant/constant.go | Cookie Key、Header Key、Token Key 定义 |
导出函数一览
| 函数 | 签名 | 说明 |
|---|---|---|
config.Init | Init(viper *viper.Viper) | 初始化 SDK 配置 |
middleware.AuthMiddleware | func(ctx *gin.Context) | 认证中间件 |
middleware.Authenticate | func(ctx *gin.Context) bool | 认证逻辑,可直接调用 |
util.GetAccountInfo | (ctx *gin.Context) *model.AccountInfo | 获取完整账号信息 |
util.GetTenantId | (ctx *gin.Context) string | 获取租户 ID |
util.GetAccountId | (ctx *gin.Context) string | 获取账号 ID |
util.GetUserId | (ctx *gin.Context) string | 获取用户 ID |
util.GetToken | (ctx *gin.Context) string | 从请求中获取用户 Token |
util.ApplyToken | () string | 获取应用账号 Token(内部缓存 3600 秒) |
util.ValidateToken | (tokenStr string) bool | 校验 Token 签名与有效期 |
util.ParseAccountInfo | (tokenStr string) model.AccountInfo | 解析 Token 中的账号信息 |
util.InitKeys | () | 显式初始化公钥(通常由校验函数自动调用) |
util.Request | (uri, method, body string, auth bool) []byte | 发起 HTTP 请求 |
util.RequestWithAuth | (uri, method, body string) []byte | 发起携带应用 Token 的 HTTP 请求 |
util.NewPathPatternParser | () *PathPatternParser | 创建路径模式解析器 |
API 对比
| 功能 | Java SDK | Go SDK |
|---|---|---|
| 框架 | Spring Boot | Gin |
| 配置方式 | @ConfigurationProperties + @EnableConfigurationProperties | Viper + YAML 配置文件 |
| 中间件 | Servlet Filter | Gin Middleware |
| Token 验证 | JJWT | golang-jwt/jwt |
| Token 传递 | Cookie + Header | Cookie passport_token + Header passport-token |
| Token 算法 | ES256 | ES256 |
| 路径匹配 | Spring AntPathMatcher | 自定义路径模式解析(pkg/util/path_parser.go) |
| 权限校验 | 支持 | 尚未实现 |
公开接口
Passport 提供了一套完整的 REST API,供开发者在任意语言或框架的应用中调用,实现认证鉴权功能。
本文档以
passport-service的路由注册(internal/router/router.go)为基准编写,所有接口路径、参数与响应结构均取自当前实现。
Base URL
根据部署环境选择:
# 生产环境
https://passport.vancone.com
# 测试环境(仅限内网访问)
http://passport.beta.vancone.com
所有接口统一前缀为 /api/passport/service/v1。
请求说明
认证方式
Token 通过以下两种方式之一传递,服务端优先读取 Cookie:
| 方式 | 名称 |
|---|---|
| Cookie | passport_token |
| 请求头 | passport-token |
登录成功后,服务端会同时下发两个 Cookie:passport_token(Token)与 passport_username(用户名或登录名)。
需要认证的接口
服务端按 passport.filter.url-patterns 配置对匹配的路由做 Token 校验,未匹配的路径不做校验。默认需要携带 Token 的接口为:
| 路径 | 说明 |
|---|---|
/api/passport/service/v1/account | 账号查询、更新(创建 POST 除外) |
/api/passport/service/v1/account/* | 登录历史、找回密码等子路径 |
/api/passport/service/v1/account-profile | 用户资料 |
/api/passport/service/v1/account-profile/* | 头像 |
/api/passport/service/v1/sync/* | 同步接口 |
/api/passport/service/v1/query/* | 分页查询 |
显式的免校验规则(代码硬编码,不受配置影响):
POST /api/passport/service/v1/account(账号注册)/api/passport/service/v1/account/forgot-password/*(找回密码全流程)
请求体格式
除「验证滑块验证码」接口使用 application/x-www-form-urlencoded 外,其余接口请求与响应均为 JSON 格式。
响应格式
所有响应遵循统一格式:
{
"code": 0,
"message": "success",
"data": { ... }
}
| 字段 | 说明 |
|---|---|
| code | 业务状态码,0 表示成功,其他值表示失败 |
| message | 响应消息 |
| data | 响应数据,无数据时该字段被省略 |
HTTP 状态码与业务状态码是两套独立的东西,请务必区分:
| HTTP 状态码 | 业务 code | 出现场景 |
|---|---|---|
| 200 | 0 | 成功 |
| 200 | 10001–10005、4001–4006 | 登录失败、找回密码失败。业务错误仍返回 200,必须解析 body 中的 code 判断 |
| 200 / 500 | -1 | 服务端异常、参数绑定失败等兜底错误 |
| 401 | 11002 | Token 缺失或无效 |
| 403 | 403 | 越权(例如尝试更新他人账号) |
| 404 | - | 资源不存在(如无头像时获取头像) |
API 列表
Login 模块
1.1 用户登录
GET /api/passport/service/v1/login
POST /api/passport/service/v1/login
登录必须先通过滑块验证码(见 8.2、8.3),否则会返回 10005。
请求参数(GET 走 query,POST 走 JSON body):
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| userId | string | 否 | 登录名。与 email 二选一,二者同时为空时按空账号处理 |
| string | 否 | 邮箱。userId 为空时作为登录标识 | |
| password | string | 是 | 密码明文,服务端以 BCrypt 比对 |
| captchaToken | string | 是 | 滑块验证码校验通过后返回的票据 |
| tenantId | string | 否 | 租户 ID |
响应:
{
"code": 0,
"message": "success",
"data": {
"token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9...",
"username": "admin"
}
}
响应中只有
token与username两个字段。username取账号的name,未设置name时回退为userId。
业务结果:登录成功时同时下发 passport_token 与 passport_username 两个 Cookie,有效期由服务端配置 passport.cookie.expired-seconds 决定(默认 86400 秒)。
锁定策略:连续登录失败次数超过服务端配置 passport.login-failure-times-limit(默认 5)后,账号被锁定,返回 10003;登录成功后失败计数清零。
失败响应(HTTP 200):
{
"code": 10002,
"message": "Incorrect password"
}
1.2 登出
DELETE /api/passport/service/v1/login
响应:
{
"code": 0,
"message": "success"
}
说明:清除 passport_token 与 passport_username 两个 Cookie。服务端为无状态 JWT,不维护会话黑名单,登出仅清除客户端 Cookie。
App 登出:请求体可携带 { "refreshToken": "..." },服务端会删除对应的 refresh token 记录实现服务端吊销;Web 端不带请求体,行为不变。
1.3 App 登录(桌面 / 移动端)
POST /api/passport/service/v1/login/app
供原生 App(Electron 桌面端、Android)使用的独立登录端点。与 Web 登录(1.1)的区别:
- 不种 Cookie,Token 由客户端自行安全存储;
- 响应额外返回
refreshToken(有效期 30 天),用于静默续期(见 2.5); - 登录历史中的
clientType记录客户端类型。
请求体:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| userId | string | 否 | 登录名。与 email 二选一 |
| string | 否 | 邮箱 | |
| password | string | 是 | 密码明文 |
| captchaToken | string | 是 | 滑块验证码票据(见 8.3),App 端同样必须过滑块 |
| tenantId | string | 否 | 租户 ID |
| clientType | string | 否 | 客户端类型:DESKTOP / ANDROID,缺省 APP |
响应:
{
"code": 0,
"message": "success",
"data": {
"token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9...",
"username": "admin",
"refreshToken": "kN9xQ2p...43位URL安全随机串"
}
}
失败语义与 1.1 完全一致(HTTP 200 + 业务码 10001~10005)。
设计说明:App 登录与 Web 登录是两个独立端点(逻辑同一套,契约分开)——Token 生命周期、安全策略、后续废弃节奏(迁移 OIDC PKCE)都按客户端独立演进。
1.4 扫码登录
扫码登录(Web 展示二维码 + 扫码设备确认)包含创建会话、轮询状态、上报扫码、确认登录四个接口,已独立成文,见「扫码登录接入」。
Token 模块
2.1 生成签名
应用账号换取 Token 的第一步。
POST /api/passport/service/v1/token/signature
请求体:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| accessKeyId | string | 是 | 应用账号的 Access Key ID |
| secretAccessKey | string | 是 | 应用账号的 Secret Access Key |
响应:
{
"code": 0,
"message": "success",
"data": {
"signature": "ABCDEF123456...",
"timestamp": "1640000000000"
}
}
签名计算方式(服务端实现,客户端调用本接口即可,无需自行计算):
timestamp = 当前毫秒时间戳
signature = UPPER(HEX(HMAC-SHA256(secretAccessKey, accessKeyId + timestamp)))
2.2 生成 Token
POST /api/passport/service/v1/token
请求体:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| accessKeyId | string | 是 | Access Key ID |
| timestamp | string | 是 | 上一步返回的毫秒时间戳 |
| signature | string | 是 | 上一步返回的签名 |
响应:data 为 Token 字符串(不是对象)。
{
"code": 0,
"message": "success",
"data": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9..."
}
签名校验失败时返回 HTTP 500、code 为 -1,message 为 signature validation failed。
2.3 验证 Token
POST /api/passport/service/v1/token/validate
请求体:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| token | string | 是 | 要验证的 Token |
响应:data 为 布尔值。
{
"code": 0,
"message": "success",
"data": true
}
2.4 获取 Token 剩余有效期
POST /api/passport/service/v1/token/expiration
请求体:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| token | string | 是 | 要查询的 Token |
响应:data 为剩余秒数(整数)。
{
"code": 0,
"message": "success",
"data": 86399
}
说明:Token 无效或已过期时返回 0。Token 有效期固定为签发后 24 小时,不支持续期,过期后需重新登录或重新申请。
2.5 刷新 Token(App)
POST /api/passport/service/v1/token/refresh
使用 1.3 返回的 refreshToken 换取新的 access token 与新的 refresh token。旋转式:旧 refreshToken 在本次调用中被消费,立即作废。
请求体:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| refreshToken | string | 是 | 1.3 或上次刷新返回的 refreshToken |
响应:
{
"code": 0,
"message": "success",
"data": {
"token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "新的refreshToken"
}
}
说明:
- 新 access token 按服务端存储的账号重新签发,权限变更在刷新后即时生效;
refreshToken无效或已过期返回 HTTP 401 /code 11002,客户端应回到登录页;- 该接口免滑块:
refreshToken本身即凭证; - 登出时携带
refreshToken调用DELETE /login可在服务端吊销(见 1.2)。
Token 结构
Token 为 ES256 签名的 JWT,Claims 如下:
| Claim | 说明 |
|---|---|
acid | 账号 ID |
uid | 用户 ID(登录名) |
tid | 租户 ID |
pids | 权限 ID 数组 |
exp | 过期时间(签发时间 + 24 小时) |
Account 模块
3.1 查询当前账号信息
GET /api/passport/service/v1/account
需要携带 Token。返回的是 Token 中 acid 对应的账号。
响应:
{
"code": 0,
"message": "success",
"data": {
"id": "1234567890",
"userId": "user123",
"type": "PERSONAL",
"name": "张三",
"email": "user@example.com",
"phone": "13800138000",
"tenantId": "0",
"applicationId": ""
}
}
字段说明:
| 字段 | 说明 |
|---|---|
| id | 账号 ID(雪花 ID),即 Token 中的 acid 声明 |
| userId | 登录名 |
| type | 账号类型:PERSONAL(个人账号)或 SERVICE(应用账号) |
| name | 账号名称 |
| email / phone | 邮箱、手机号,为空时字段被省略 |
| tenantId | 租户 ID |
| applicationId | 所属应用 ID,仅应用账号有值 |
| loginFailureCount | 连续登录失败次数,为 0 时字段被省略 |
- 出于安全考虑,响应中不包含
password字段。lastLoginTime、birthDay、applicationName为派生字段,当前实现不会填充,响应中不会出现。生日信息请通过「用户资料」接口获取(见 4.1,字段名为birthday)。
3.2 创建账号(注册)
POST /api/passport/service/v1/account
该接口免 Token 校验。
请求体:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| userId | string | 是 | 登录名 |
| type | string | 是 | 账号类型:PERSONAL 或 SERVICE |
| name | string | 否 | 账号名称 |
| password | string | 否 | 密码。个人账号建议必填 |
| string | 否 | 邮箱地址 | |
| phone | string | 否 | 手机号码 |
| applicationId | string | 否 | 所属应用 ID,仅应用账号需要 |
响应:与 3.1 相同的账号对象。
说明:当前版本注册不需要邮箱验证码,注册完成即可登录,账号没有「待激活」状态。密码复杂度仅由前端校验,服务端未做强制约束,接入方如需约束请自行在业务侧实现。
3.3 更新账号
PUT /api/passport/service/v1/account
需要携带 Token。
请求体:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | string | 是 | 账号 ID,必须与 Token 中的 acid 一致,否则返回 403 |
| name | string | 否 | 账号名称 |
| string | 否 | 邮箱地址,找回密码时使用 | |
| phone | string | 否 | 手机号码 |
响应:
{
"code": 0,
"message": "success"
}
重要警告:该接口采用全量保存。请求体中不要携带
password字段——若携带,提交的明文会直接覆盖数据库中的 BCrypt 密文,导致该账号永久无法登录。当前版本没有提供修改密码接口,修改密码请走「找回密码」流程(见 9.1–9.3)。
Account Profile 模块
4.1 查询用户资料
GET /api/passport/service/v1/account-profile
需要携带 Token。
响应:
{
"code": 0,
"message": "success",
"data": {
"id": "1234567890",
"name": "张三",
"gender": "MALE",
"birthday": "1990-01-01",
"bio": "这是一段个人简介",
"avatar": "/api/passport/service/v1/account-profile/avatar",
"updatedTime": "2024-01-01 10:00:00"
}
}
| 字段 | 说明 |
|---|---|
| id | 账号 ID,与账号的 id 相同 |
| name | 姓名 |
| gender | 性别:MALE / FEMALE / OTHERS |
| birthday | 生日 |
| bio | 个人简介 |
| avatar | 头像访问路径。已上传头像时为该固定路径,未上传时为空字符串 |
| updatedTime | 更新时间 |
资料中不包含
phone,这两个字段属于账号(Account)而非资料(Profile)。
4.2 更新用户资料
PUT /api/passport/service/v1/account-profile
需要携带 Token。
请求体:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| name | string | 否 | 姓名 |
| gender | string | 否 | 性别:MALE / FEMALE / OTHERS |
| birthday | string | 否 | 生日(格式:YYYY-MM-DD) |
| bio | string | 否 | 个人简介 |
响应:
{
"code": 0,
"message": "success"
}
说明:资料的 id 由服务端从 Token 中取,不读取请求体中的 id,因此无法修改他人资料。
4.3 获取头像
GET /api/passport/service/v1/account-profile/avatar
需要携带 Token。返回当前账号的头像图片二进制流。
未上传头像时返回 HTTP 404,且不返回 JSON 响应体。
4.4 上传头像
POST /api/passport/service/v1/account-profile/avatar
需要携带 Token。使用 multipart/form-data 上传。
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| file | file | 是 | 头像文件。仅支持 .jpg / .jpeg / .png / .gif |
响应:
{
"code": 0,
"message": "success",
"data": "/api/passport/service/v1/account-profile/avatar"
}
说明:文件以「账号 ID + 原扩展名」命名,上传新头像会覆盖同账号的旧头像文件。
Query 模块
5.1 分页查询账号
GET /api/passport/service/v1/query/account
需要携带 Token。
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| pageNo | int | 否 | 页码,默认 1 |
| pageSize | int | 否 | 每页数量,默认 10 |
| search | string | 否 | 搜索关键字 |
| accountId | string | 否 | 指定账号 ID 查询 |
响应:
{
"code": 0,
"message": "success",
"data": {
"list": [
{
"id": "1234567890",
"userId": "user123",
"name": "张三"
}
],
"pageNo": 1,
"pageSize": 10,
"totalCount": 100,
"totalPage": 10
}
}
分页查询仅返回
id、userId、name三个字段,不包含邮箱、手机号等信息。如需完整账号信息,请先按id调用 3.1 查询账号接口。
分页字段说明:
| 字段 | 说明 |
|---|---|
| list | 当前页数据 |
| pageNo | 当前页码 |
| pageSize | 每页数量 |
| totalCount | 总记录数 |
| totalPage | 总页数 |
Login History 模块
6.1 查询登录历史
GET /api/passport/service/v1/account/login-history
需要携带 Token。返回当前账号最近的登录记录。
响应:
{
"code": 0,
"message": "success",
"data": [
{
"accountId": "1234567890",
"clientIp": "192.168.1.1",
"loginMethod": "WEB",
"LoginTime": "2024-01-01 10:00:00"
}
]
}
| 字段 | 说明 |
|---|---|
| accountId | 账号 ID |
| clientIp | 登录 IP |
| clientType | 客户端类型:DESKTOP / ANDROID / APP,Web 登录时该字段被省略 |
| loginMethod | 登录方式:WEB(页面登录)、API(接口换取 Token)或 QR_CODE(扫码登录) |
| LoginTime | 登录时间。注意该字段的 JSON 键首字母为大写,与其他字段风格不一致,取值时请照此处理 |
Sync 模块
用于应用账号(SDK 接入方)同步自身应用下的 API 与权限定义。需要携带应用账号的 Token。
7.1 同步 API 列表
GET /api/passport/service/v1/sync/api
响应:
{
"code": 0,
"message": "success",
"data": [
{
"id": "api123",
"name": "查询用户",
"path": "/api/user/*",
"method": "GET",
"description": "查询用户信息",
"applicationId": "app123",
"tenantId": "0",
"creator": "admin",
"updater": "admin",
"createdTime": "2024-01-01 10:00:00",
"updatedTime": "2024-01-01 10:00:00"
}
]
}
说明:返回当前应用账号所属应用的 API 列表。若账号未绑定应用,返回空数组。
7.2 同步权限列表
GET /api/passport/service/v1/sync/permission
响应:
{
"code": 0,
"message": "success",
"data": [
{
"id": "permission123",
"name": "用户管理权限",
"description": "用户管理相关权限",
"applicationId": "app123",
"applicationName": "用户服务",
"riskLevel": "LOW",
"apiCount": 5,
"tenantId": "0",
"creator": "admin",
"updater": "admin",
"createdTime": "2024-01-01 10:00:00",
"updatedTime": "2024-01-01 10:00:00",
"apiIds": ["api1", "api2", "api3", "api4", "api5"]
}
]
}
说明:权限归属应用,字段为 applicationId / applicationName(早期版本中的 serviceId / serviceName 已废弃)。
7.3 同步标志
GET /api/passport/service/v1/sync/flag
该接口尚未实现,当前调用会返回 HTTP 500。请勿在生产环境依赖此接口。
Verify 模块
8.1 生成邮箱验证码
GET /api/passport/service/v1/verify?email=user@example.com
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| string | 是 | 邮箱地址 |
响应:data 为 null,验证码通过邮件发送。
{
"code": 0,
"message": "success"
}
8.2 生成滑块验证码
GET /api/passport/service/v1/verify/image
响应:返回滑块验证码素材,不是图片流。
{
"code": 0,
"message": "success",
"data": {
"key": "captcha:xxxxxxxx",
"imageBase64": "iVBORw0KGgoAAAANSUhEUg...",
"tileBase64": "iVBORw0KGgoAAAANSUhEUg...",
"tileWidth": 60,
"tileHeight": 60,
"tileX": 120,
"tileY": 45
}
}
| 字段 | 说明 |
|---|---|
| key | 验证码标识,提交校验时回传 |
| imageBase64 | 底图(Base64) |
| tileBase64 | 滑块拼图块(Base64) |
| tileWidth / tileHeight | 拼图块尺寸 |
| tileX / tileY | 拼图块在底图中的目标位置 |
出于安全考虑,
tileX(缺口横坐标)由服务端返回,接入方据此渲染初始位置并采集用户拖动轨迹。
8.3 校验滑块验证码
POST /api/passport/service/v1/verify/image
该接口使用表单格式(application/x-www-form-urlencoded),不是 JSON。
请求参数:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| point | string | 是 | 用户拖动滑块的落点坐标,格式 "x,y",例如 "118,45" |
| key | string | 是 | 8.2 返回的 key |
响应:
{
"code": 0,
"message": "success",
"data": {
"captchaToken": "captcha:token:xxxxxxxx",
"ok": true
}
}
说明:校验容差为 4 像素。ok 为 false 表示校验未通过,此时 captchaToken 为空。校验通过后返回的 captchaToken 用于登录(1.1)与找回密码(8.4),且为一次性凭证。
Forgot Password 模块
修改密码需通过以下三段式流程完成,该模块全部接口免 Token 校验。流程起点仍需先过滑块验证码。
9.1 发送验证码
POST /api/passport/service/v1/account/forgot-password/send-code
请求体:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| captchaToken | string | 是 | 滑块验证码票据(见 8.3) |
| string | 是 | 注册时使用的邮箱 |
响应:
{
"code": 0,
"message": "success"
}
失败时返回 HTTP 200 与对应的业务码(见「错误码」),例如 4001 Email not registered。
9.2 校验验证码
POST /api/passport/service/v1/account/forgot-password/verify-code
请求体:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| string | 是 | 邮箱 | |
| code | string | 是 | 邮件中的验证码 |
响应:
{
"code": 0,
"message": "success",
"data": {
"resetToken": "xxxxxxxx"
}
}
9.3 重置密码
POST /api/passport/service/v1/account/forgot-password/reset
请求体:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| string | 是 | 邮箱 | |
| resetToken | string | 是 | 8.5 返回的 resetToken |
| newPassword | string | 是 | 新密码 |
响应:
{
"code": 0,
"message": "success"
}
完整流程:
- 调用 8.2 获取滑块验证码素材
- 调用 8.3 提交滑块位置,换取
captchaToken - 调用 9.1(携带
captchaToken与邮箱)发送邮件验证码 - 调用 9.2(携带邮箱与邮件验证码)换取
resetToken - 调用 9.3(携带邮箱、
resetToken、新密码)完成重置
错误码
通用
| 错误码 | HTTP 状态码 | 说明 |
|---|---|---|
| 0 | 200 | 成功 |
| -1 | 500 | 服务端异常或参数绑定失败,message 为具体错误描述 |
| 403 | 403 | 越权操作 |
| 11002 | 401 | Token 缺失或无效({"code":11002,"message":"Not authorized"}) |
登录(Login)
| 错误码 | 说明 |
|---|---|
| 10001 | Account not found(账号不存在) |
| 10002 | Incorrect password(密码错误) |
| 10003 | Account locked due to too many failed attempts(失败次数超限,账号已锁定) |
| 10004 | Account is disabled(账号已禁用) |
| 10005 | Captcha verification failed(滑块验证码校验失败) |
以上错误码均伴随 HTTP 200 返回,请通过 body 中的
code判断,不要只看 HTTP 状态码。
找回密码(Forgot Password)
| 错误码 | 说明 |
|---|---|
| 4001 | Email not registered(邮箱未注册) |
| 4002 | Invalid verification code(验证码错误) |
| 4003 | Verification code expired(验证码已过期) |
| 4004 | Invalid reset token(resetToken 无效) |
| 4005 | Too many attempts(尝试次数过多) |
| 4006 | Captcha verification failed(滑块验证码校验失败) |
| 5001 | Unknown error(兜底错误) |
同样伴随 HTTP 200 返回。
管理端(passport-admin)
管理端服务使用独立的错误码空间:
| 错误码 | 说明 |
|---|---|
| 10001 | Forbidden(无权限) |
| 10002 | 资源 ID 重复 |
| 10004 | 参数非法 |
认证流程
个人账号登录流程
- 调用「生成滑块验证码」获取验证码素材
- 调用「校验滑块验证码」提交滑块位置,换取
captchaToken - 调用「用户登录」,携带
captchaToken、登录名、密码 - 保存返回的
token,后续请求在passport-token请求头或passport_tokenCookie 中携带
扫码登录流程
Web 端与扫码设备端的完整接入步骤见「扫码登录接入」的「接入清单」。
App 登录与续期流程
- 调用「生成滑块验证码」+「校验滑块验证码」换取
captchaToken - 调用「App 登录」(1.3),安全保存返回的
token与refreshToken - access token 过期(或收到 401)时,调用「刷新 Token」(2.5)静默续期;刷新失败则回登录页
- 登出时携带
refreshToken调用DELETE /login,服务端吊销后清除本地存储
应用账号换取 Token 流程
- 调用「生成签名」,传入
accessKeyId与secretAccessKey,获得signature与timestamp - 调用「生成 Token」,传入
accessKeyId、timestamp、signature - 保存返回的 Token 字符串,后续请求在
passport-token请求头中携带 - Token 有效期 24 小时且不支持续期,过期后重新执行本流程(SDK 已内置该流程与缓存,参见「SDK 集成」章节)
权限判断
Token 的 pids 声明中携带了账号被授予的权限 ID 列表。接入方有两种做法:
- 直接解析 JWT 的
pids声明(需持有公钥校验签名) - 调用「同步权限列表」接口获取权限定义,与
pids比对
注意:Go SDK 当前版本不会解析
pids,AccountInfo.PermissionIds字段恒为空,需自行解析。
扫码登录接入
扫码登录允许已登录的 VanCone App 用户通过扫描二维码帮助网页完成登录,无需在网页上输入账号密码。本文档描述扫码登录的完整接口契约;常规登录、Token 等其余接口见「公开接口」。
扫码登录涉及两侧调用方:
- Web 端(登录页):创建会话、展示二维码、轮询状态;
- 扫码设备端(VanCone App):解析二维码、上报扫码、确认登录。
会话状态保存在服务端(Redis),有效期 120 秒。
总体流程
Web 浏览器 Passport Service 扫码设备(App)
│ 创建扫码会话 │ │
│─────────────────────────────────>│ 生成一次性 authCode │
│<─── authCode ────────────────────│ │
│ 渲染二维码 │ │
│ 查询状态(每 2s 轮询) │ 上报已扫码 ─────────────│
│─────────────────────────────────>│<─────────────────────────────│
│<─── {status: scanned} ───────────│ 确认登录 ──────────────│
│ │<─────────────────────────────│
│ 查询状态 │ 确认态原子消费,签发 Token │
│─────────────────────────────────>│ + 下发 Cookie │
│<─── {status: confirmed, token} ──│ │
│ 登录完成,跳转回来源页面 │ │
二维码内容约定
二维码内容为自定义协议串:
vancone://login-by-qrcode?auth-code={authCode}
扫码设备解析出 authCode 后,调用下方「上报已扫码」与「确认登录」接口。
接口明细
所有请求与响应均为 JSON,统一前缀 /api/passport/service/v1,响应遵循 Passport 标准结构 {code, message, data}(见「公开接口」的响应格式说明)。
1. 创建扫码会话(Web 调用,免 Token)
POST /api/passport/service/v1/login/qrcode
响应:
{
"code": 0,
"message": "success",
"data": {
"authCode": "8fJ3kQ2p...32位URL安全随机串",
"expiredSeconds": 120
}
}
| 字段 | 说明 |
|---|---|
| authCode | 一次性会话码,由密码学安全随机数生成(32 字符 URL 安全串)。持有它即可完成登录,不要泄露 |
| expiredSeconds | 会话有效期(秒),过期后需重新创建 |
2. 查询扫码状态(Web 调用,免 Token)
GET /api/passport/service/v1/login/qrcode/{authCode}
Web 端以此轮询,建议间隔 2 秒。status 取值:
| status | 说明 |
|---|---|
pending | 已创建,等待扫码 |
scanned | 扫码设备已上报扫码,等待用户在手机上确认 |
confirmed | 确认完成。本响应同时下发 passport_token / passport_username Cookie,data 中附带 token 与 username;且会话被本次轮询原子消费,后续再查询一律返回 expired,Token 不可通过重复轮询二次获取 |
expired | 不存在或已过期 |
{
"code": 0,
"message": "success",
"data": {
"status": "confirmed",
"token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9...",
"username": "admin"
}
}
3. 上报已扫码(扫码设备调用,需要 Token)
POST /api/passport/service/v1/login/qrcode/{authCode}/scan
认证方式与其他接口相同(passport-token 请求头或 passport_token Cookie)。幂等:重复上报返回成功。
4. 确认登录(扫码设备调用,需要 Token)
POST /api/passport/service/v1/login/qrcode/{authCode}/confirm
认证方式同上。幂等:重复确认返回成功(直到会话被 Web 端消费)。允许从 pending 直接确认——设备可将「扫码」与「确认」合并为一步。确认成功后,Web 端的下一次轮询即拿到 confirmed 与 Token。
错误返回
| 场景 | HTTP 状态码 | code | message |
|---|---|---|---|
| 会话不存在或已过期(scan / confirm) | 500 | -1 | qrcode login session not found or expired |
| 会话状态非法流转(如确认已被消费的会话) | 500 | -1 | invalid qrcode login session state |
| scan / confirm 未携带有效 Token | 401 | 11002 | Not authorized |
| 创建会话服务端异常(如 Redis 不可用) | 500 | -1 | 具体错误描述 |
查询状态接口不返回错误码:会话过期体现在
status: expired中,HTTP 状态码仍为 200。
安全要点
authCode一次性有效:确认后被 Web 端轮询取走即从服务端删除,防重放- scan / confirm 必须携带扫码设备自身的有效登录态,未登录设备无法确认
- 会话有效期仅 120 秒,过期必须重新创建,避免长期挂起的待确认会话
- 登录成功会写入登录历史,
loginMethod为QR_CODE(见「公开接口」的登录历史一节)
接入清单
Web 端(登录页):
- 调用「创建扫码会话」,将
authCode按约定格式渲染为二维码 - 每 2 秒调用「查询扫码状态」,展示 pending / scanned / expired
- 轮询到
confirmed即登录完成:服务端已在该响应中下发 Cookie - 会话过期后重新执行第 1 步
扫码设备端(App):
- 扫码解析出
authCode - 调用「上报已扫码」(需要设备自身的有效 Token)
- 用户确认后调用「确认登录」完成登录
服务与组件清单
Passport 由以下服务与组件构成。
后端服务
| 服务 | 仓库目录 | 类型 | 默认端口 | 说明 |
|---|---|---|---|---|
passport-service | passport/passport-service | 后端(Go / Gin) | 10010 | 认证服务。处理注册、登录、Token 签发与校验、账号资料、验证码、找回密码、同步接口 |
passport-admin | passport/passport-admin | 后端(Go / Gin) | 10011 | 管理服务。提供租户、账号、群组、权限、应用、应用 API 的管理接口 |
前端应用
| 应用 | 仓库目录 | 技术栈 | 说明 |
|---|---|---|---|
passport-web | passport/passport-web | Vue 3 + TypeScript | 用户界面,提供注册、登录、个人中心 |
passport-admin-web | passport/passport-admin-web | Vue 3 + TypeScript | 管理界面,提供租户、账号、群组、权限、应用的管理页面 |
SDK
| SDK | 位置 | 适用框架 | 说明 |
|---|---|---|---|
| Java SDK | passport/passport-sdk-java | Spring Boot | 通过 Servlet Filter 实现认证鉴权拦截,当前版本 0.1.4 |
| Go SDK | vancone-passport-sdk-go(独立仓库) | Gin | 通过 Gin 中间件实现认证拦截 |
Go SDK 不在
passport主仓库内,位于独立仓库github.com/vancone/vancone-passport-sdk-go。
依赖的基础设施
| 组件 | 用途 |
|---|---|
| MySQL | 持久化业务数据(账号、租户、群组、权限、应用、API、登录历史等) |
| Redis | 缓存验证码、Token 签名、防重放相关数据 |
| SMTP 邮件服务 | 发送邮箱验证码 |
文档
| 文档 | 位置 | 说明 |
|---|---|---|
| 产品手册 | docs/product-documents/passport-product-document | 本文档 |
| 服务文档 | passport/passport-doc | 开发侧设计文档 |