产品介绍

VanCone Passport 是覆盖企业组织和个人用户全场景的统一身份认证和权限管控服务,集成了通用的 SSO 单点登录和 RBAC 鉴权机制,旨在为用户提供账户注册与登录、授权鉴权等功能。用户在 Passport 平台上注册账号之后,就相当于持有统一的服务通行证,可以登录使用所有集成 Passport 认证的应用服务。各个业务应用无需单独构建登录和鉴权能力,用户在不同应用之间跳转也无需重复登录。

欢迎体验 Passport 服务:

核心特性

统一身份认证

  • 支持邮箱注册、密码登录
  • 登录需通过滑块验证码,防止自动化攻击
  • 邮箱验证码机制,用于找回密码
  • 支持 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
SDKJava 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_session Cookie)的认证方式已在 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、登录名(userIdemail)与密码调用登录接口。

captchaToken 是登录的必填参数。未携带或校验未通过时,登录接口直接返回 10005 Captcha verification failed,不会校验密码。

登录成功

  • 响应体中返回 tokenusername
  • 同时下发两个 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

第一步:提交 accessKeyIdsecretAccessKey,服务端返回签名与毫秒时间戳。签名算法为:

signature = UPPER(HEX(HMAC-SHA256(secretAccessKey, accessKeyId + timestamp)))

第二步:提交 accessKeyIdtimestampsignature 换取 Token。服务端会重新计算签名比对,并校验应用账号凭证是否存在。

使用 SDK 时,上述两步与 Token 缓存均由 SDK 内部完成,无需手动调用。Go SDK 的 Token 缓存周期为 3600 秒。

服务端如何校验请求

passport-service 按下述顺序处理每一个请求:

  1. 请求路径命中配置的鉴权路径模式时进入校验,否则直接放行
  2. 注册接口(POST /account)与找回密码接口(/account/forgot-password/*)显式豁免
  3. 优先从 Cookie passport_token 读取 Token,为空时读取请求头 passport-token
  4. 校验签名与有效期
  5. 校验通过则将 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 密文,导致账号永久无法登录。

基础操作

基础操作面向普通用户,介绍如何注册账号、登录系统以及使用个人中心管理自己的信息。

注册账号

注册账号需要提供邮箱地址和用户自定义密码。注册完成后即可登录,无需邮箱激活。

注册步骤

  1. 访问 Passport 注册页面
  2. 填写注册信息:
    • 用户名(登录标识,全局唯一)
    • 邮箱地址(用于找回密码)
    • 密码
    • 确认密码
  3. 点击「注册」按钮
  4. 注册完成,跳转到登录页

注意事项

  • 用户名必须唯一,不能与已有账号重复
  • 密码需要满足一定的复杂度要求(长度不少于 8 位,包含大小写字母、数字和特殊字符)
  • 邮箱地址必须真实有效——它是后续找回密码的唯一途径
  • 密码复杂度目前仅由页面前端校验

登录账号

账号注册完成后,即可使用用户名或邮箱登录系统。

登录步骤

  1. 访问 Passport 登录页面
  2. 输入用户名或邮箱地址、密码
  3. 完成滑块验证码:拖动滑块,将拼图块对齐到缺口位置
  4. 点击「登录」按钮

滑块验证码是登录的必经环节。未通过验证将无法提交登录,服务端会直接返回「验证码校验失败」,不会校验密码。

登录失败与账号锁定

连续登录失败超过 5 次后,账号会被锁定,需等待管理员处理或联系技术支持。登录成功后失败计数清零。

可能出现的结果:

提示说明
账号不存在用户名或邮箱未注册
密码错误密码不正确
账号已锁定连续失败次数超限
账号已禁用账号被管理员停用
验证码校验失败滑块验证码未通过或已失效

扫码登录

登录页支持扫码登录:页面展示一张动态二维码,使用已登录的 VanCone App 扫码并在手机上确认后,网页自动完成登录并跳转回来源页面。

操作步骤

  1. 在登录页切换到扫码登录
  2. 打开 VanCone App,使用扫一扫识别页面上的二维码
  3. 在手机上确认登录
  4. 网页显示「登录成功」后自动跳转,无需输入账号密码

二维码状态

状态说明
等待扫码二维码有效,等待 App 扫码
已扫码App 已识别二维码,等待用户在手机上确认
登录成功确认完成,网页自动跳转
二维码已过期二维码有效期为 120 秒,过期后点击「点击刷新」重新获取

注意事项

  • 二维码一次性有效,确认登录后立即作废,不能重复使用
  • 二维码过期后原码作废,必须刷新后重新扫码
  • 扫码登录会记录在登录历史中,登录方式为「扫码」
  • App 端扫码功能在后续版本提供,发布前扫码入口暂不可完成确认操作

单点登录

当用户登录 Passport 后,会获得一个有效的 Token。该 Token 通过 Cookie 和 Header 两种方式传递给后续访问的应用。已集成 Passport 的应用会自动识别该 Token,实现免登录访问,这就是 SSO 单点登录机制。

Token 有效期

Token 有效期为登录后 24 小时,不支持自动续期。过期后需要重新登录。

登出账号

用户可以主动退出登录,清除本地 Token。

登出步骤

  1. 在任意已集成的应用中找到「登出」按钮
  2. 点击后系统会清除 Token
  3. 退出后需要重新登录才能访问受保护的资源

找回密码

如果用户忘记密码,可以通过注册邮箱找回。找回流程为「滑块验证码 → 邮箱验证码 → 重置密码」三段式。

找回步骤

  1. 在登录页面点击「忘记密码」
  2. 完成滑块验证码
  3. 输入注册邮箱地址,系统发送验证码邮件
  4. 打开邮件,输入邮件中的验证码
  5. 设置新密码并提交

注意事项

  • 只能通过注册邮箱找回密码
  • 邮箱验证码和重置凭证都有时效性,请尽快完成
  • 重置密码后原密码立即失效
  • 已登录状态下的「修改密码」功能当前版本未提供,忘记密码时请使用本流程

基础操作

基础操作面向普通用户,介绍如何注册账号、登录系统以及使用个人中心管理自己的信息。

注册账号

注册账号需要提供邮箱地址和用户自定义密码。注册完成后即可登录,无需邮箱激活。

注册步骤

  1. 访问 Passport 注册页面
  2. 填写注册信息:
    • 用户名(登录标识,全局唯一)
    • 邮箱地址(用于找回密码)
    • 密码
    • 确认密码
  3. 点击「注册」按钮
  4. 注册完成,跳转到登录页

注意事项

  • 用户名必须唯一,不能与已有账号重复
  • 密码需要满足一定的复杂度要求(长度不少于 8 位,包含大小写字母、数字和特殊字符)
  • 邮箱地址必须真实有效——它是后续找回密码的唯一途径
  • 密码复杂度目前仅由页面前端校验

登录账号

账号注册完成后,即可使用用户名或邮箱登录系统。

登录步骤

  1. 访问 Passport 登录页面
  2. 输入用户名或邮箱地址、密码
  3. 完成滑块验证码:拖动滑块,将拼图块对齐到缺口位置
  4. 点击「登录」按钮

滑块验证码是登录的必经环节。未通过验证将无法提交登录,服务端会直接返回「验证码校验失败」,不会校验密码。

登录失败与账号锁定

连续登录失败超过 5 次后,账号会被锁定,需等待管理员处理或联系技术支持。登录成功后失败计数清零。

可能出现的结果:

提示说明
账号不存在用户名或邮箱未注册
密码错误密码不正确
账号已锁定连续失败次数超限
账号已禁用账号被管理员停用
验证码校验失败滑块验证码未通过或已失效

扫码登录

登录页支持扫码登录:页面展示一张动态二维码,使用已登录的 VanCone App 扫码并在手机上确认后,网页自动完成登录并跳转回来源页面。

操作步骤

  1. 在登录页切换到扫码登录
  2. 打开 VanCone App,使用扫一扫识别页面上的二维码
  3. 在手机上确认登录
  4. 网页显示「登录成功」后自动跳转,无需输入账号密码

二维码状态

状态说明
等待扫码二维码有效,等待 App 扫码
已扫码App 已识别二维码,等待用户在手机上确认
登录成功确认完成,网页自动跳转
二维码已过期二维码有效期为 120 秒,过期后点击「点击刷新」重新获取

注意事项

  • 二维码一次性有效,确认登录后立即作废,不能重复使用
  • 二维码过期后原码作废,必须刷新后重新扫码
  • 扫码登录会记录在登录历史中,登录方式为「扫码」
  • App 端扫码功能在后续版本提供,发布前扫码入口暂不可完成确认操作

单点登录

当用户登录 Passport 后,会获得一个有效的 Token。该 Token 通过 Cookie 和 Header 两种方式传递给后续访问的应用。已集成 Passport 的应用会自动识别该 Token,实现免登录访问,这就是 SSO 单点登录机制。

Token 有效期

Token 有效期为登录后 24 小时,不支持自动续期。过期后需要重新登录。

登出账号

用户可以主动退出登录,清除本地 Token。

登出步骤

  1. 在任意已集成的应用中找到「登出」按钮
  2. 点击后系统会清除 Token
  3. 退出后需要重新登录才能访问受保护的资源

找回密码

如果用户忘记密码,可以通过注册邮箱找回。找回流程为「滑块验证码 → 邮箱验证码 → 重置密码」三段式。

找回步骤

  1. 在登录页面点击「忘记密码」
  2. 完成滑块验证码
  3. 输入注册邮箱地址,系统发送验证码邮件
  4. 打开邮件,输入邮件中的验证码
  5. 设置新密码并提交

注意事项

  • 只能通过注册邮箱找回密码
  • 邮箱验证码和重置凭证都有时效性,请尽快完成
  • 重置密码后原密码立即失效
  • 已登录状态下的「修改密码」功能当前版本未提供,忘记密码时请使用本流程

个人中心

个人中心是用户查看和管理个人信息的地方,包含个人资料账号信息登录历史三个标签页。

个人资料

对应「用户资料(Account Profile)」,与账号本身相互独立。

可查看与修改的字段

字段说明是否可修改
头像用户头像图片是,支持 jpg / jpeg / png / gif
姓名展示用的姓名
性别男 / 女 / 其他
生日生日信息
个人简介一段自由文本,最多 200 字

修改个人资料

  1. 登录后进入个人中心的「个人资料」标签页
  2. 需要修改头像时,点击「上传头像」选择图片文件
  3. 修改其他字段后点击「保存」提交

邮箱与手机号不属于个人资料,请在「账号信息」标签页中修改。

账号信息

对应「账号(Account)」。

可查看与修改的字段

字段说明是否可修改
用户名登录系统使用的唯一标识
账号类型个人账号 / 应用账号
邮箱注册时填写的邮箱地址,找回密码时使用
手机号绑定的手机号码
所属租户账号归属的租户
上次登录时间最近一次登录的时间

修改账号信息

  1. 进入个人中心的「账号信息」标签页
  2. 修改邮箱或手机号
  3. 点击「保存」提交

注意事项

  • 用户名是登录标识,创建后不可修改
  • 修改邮箱后,找回密码将发送到新邮箱,请确保新邮箱真实有效

登录历史

系统会记录用户每次登录的详细信息:

字段说明
客户端 IP登录来源的 IP 地址
登录时间登录操作的时间
登录方式WEB(页面登录)、API(应用账号换取 Token)或 QR_CODE(扫码登录)

查看登录历史

  1. 进入个人中心
  2. 切换到「登录历史」标签页
  3. 查看最近的登录记录

登录历史可以帮助用户:

  • 发现异常登录行为
  • 追溯账号使用情况
  • 进行安全审计

修改密码

当前版本不支持在个人中心修改密码。 请改用登录页的「忘记密码」流程。

找回密码流程

  1. 在登录页面点击「忘记密码」
  2. 完成滑块验证码
  3. 输入注册邮箱,接收邮件验证码
  4. 输入邮件中的验证码
  5. 设置新密码

详细说明见「基础操作」的找回密码章节,接口说明见「公开接口」的 Forgot Password 模块。

密码要求

  • 长度不少于 8 位
  • 包含大小写字母、数字和特殊字符

密码复杂度目前仅在页面前端校验,服务端不做强制约束。通过接口直接注册或重置密码时,请接入方自行校验。

账号安全建议

  • 使用强密码:避免使用简单密码或个人信息
  • 关注登录历史:定期查看登录记录,发现异常及时处理
  • 保护邮箱安全:邮箱是找回密码的唯一途径,务必保护好
  • 注意登录锁定:连续登录失败超过 5 次账号会被锁定,成功登录后计数清零

验证服务

Passport 当前提供滑块验证码邮箱验证码两种验证方式。

人机验证(滑块验证码)

用于确认操作者是真人而非自动化程序,是登录与找回密码的必经环节

交互流程

  1. 前端调用「生成滑块验证码」接口,获取底图、拼图块与缺口位置
  2. 用户拖动滑块,前端采集落点坐标
  3. 前端调用「校验滑块验证码」接口,提交落点坐标与验证码标识
  4. 校验通过后返回 captchaToken,该票据用于后续登录或找回密码请求

校验规则

  • 落点横坐标与缺口位置相差不超过 4 像素即视为通过
  • captchaToken 为一次性凭证,使用后即失效
  • 验证码有时效性,过期后需重新获取

适用范围

场景是否需要滑块验证码
用户登录
找回密码(发送邮件验证码)
账号注册

接口说明见「公开接口」的 Verify 模块。

邮件验证

用于确认操作者拥有该邮箱的控制权,通过向邮箱发送数字验证码实现。

适用范围

场景是否需要邮箱验证码
找回密码
账号注册。注册后即可登录,账号没有待激活状态

找回密码中的使用

  1. 完成滑块验证码后,提交邮箱,系统发送验证码邮件
  2. 提交邮件中的验证码进行校验,换取 resetToken
  3. 携带 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-operatorpassport-reader并非系统内置,需要管理员在「权限管理」中自行创建后再分配。上表中的名称仅为推荐的命名方式。

从应用服务角度

鉴权机制由以下几个要素构成:

Application(应用) → API(接口)→ Permission(权限)→ Group/Account(群组/账号)

应用服务首先在 Passport 平台上建立自己的虚拟账户(应用账号),并以 AK / SK 凭证进行认证访问。开发者需要将服务的接口清单事先注册到平台上,并关联具体的权限。每个权限都有自己的所属应用。

账号管理

账号类型

系统支持两种类型的账号:

类型说明典型场景
个人账号真人用户使用的账号普通用户登录应用
应用账号服务之间调用的账号服务间 API 通信

个人账号管理

个人账号包含以下信息:

字段说明是否必填
用户 ID账号的唯一标识
用户名登录使用的用户名
邮箱邮箱地址
手机号手机号码
生日生日信息
密码登录密码(创建时必填)创建时必填

应用账号管理

应用账号用于服务间认证,包含以下信息:

字段说明是否必填
用户 ID账号的唯一标识
名称账号名称
所属应用关联的应用
描述账号描述

账号详情

在账号详情页面可以查看:

  1. 基本信息:用户名、邮箱、手机号等
  2. 关联群组:该账号加入的所有群组
  3. 账号权限:该账号直接分配的权限(包括通过群组继承的权限)
  4. 登录历史:该账号的登录记录(仅个人账号)
  5. 凭证:该账号的 Access Key 列表(仅应用账号)

创建账号

  1. 进入「账号」页面
  2. 切换到「个人账号」或「应用账号」标签
  3. 点击「创建账号」
  4. 填写账号信息
  5. 点击「确认」创建

注意:创建应用账号后,可以在详情页面查看和管理 Access Key。

群组管理

群组是用户的集合,用于批量分配权限。

群组信息

字段说明
群组名称群组的唯一名称
描述群组描述信息
创建时间群组创建时间
更新时间群组最后更新时间

群组详情

在群组详情页面可以查看:

  1. 基本信息:群组名称、描述等
  2. 群组成员:该群组包含的所有账号
  3. 群组权限:该群组拥有的权限

管理群组成员

  1. 进入群组详情
  2. 切换到「群组成员」标签
  3. 点击「添加成员」
  4. 选择要添加的账号
  5. 点击「确认」

移除成员:在成员列表中点击删除按钮即可。

管理群组权限

  1. 进入群组详情
  2. 切换到「群组权限」标签
  3. 点击「添加权限」
  4. 选择要添加的权限
  5. 点击「确认」

移除权限:在权限列表中点击删除按钮即可。

权限管理

权限是 API 接口的集合,表示一组操作能力。

权限信息

字段说明
权限名称权限的唯一名称
描述权限描述信息
所属应用权限所属的应用
接口数量该权限包含的 API 数量
创建时间权限创建时间

权限详情

在权限详情页面可以查看:

  1. 基本信息:权限名称、描述、所属应用等
  2. 关联接口:该权限包含的所有 API
  3. 授权账号:直接分配了该权限的账号(不包括通过群组继承的)

管理关联接口

  1. 进入权限详情
  2. 切换到「关联接口」标签
  3. 点击「添加接口」
  4. 选择要添加的 API
  5. 点击「确认」

移除接口:在接口列表中点击删除按钮即可。

应用管理

应用是权限管理的容器,每个应用都有自己的 API 和权限。

应用信息

字段说明
应用 ID应用的唯一标识,创建时自动生成
App Key应用的业务标识,展示在应用列表的「应用 ID」列
应用名称应用名称
描述应用描述信息
创建时间应用创建时间

应用详情

在应用详情页面可以查看:

  1. 基本信息:应用 ID、名称、描述等
  2. 权限列表:该应用下创建的所有权限
  3. 接口列表:该应用下定义的所有 API

创建应用

  1. 进入「应用」页面
  2. 点击「创建应用」
  3. 填写应用名称和描述
  4. 点击「确认」创建

创建应用后,系统会自动生成应用 ID。

已知限制:当前版本服务端在创建应用时不会自动生成 App Key。若应用列表中该列为空,需要管理员通过数据库初始化或后续版本提供的配置入口写入。

租户管理

租户用于实现多租户隔离,每个租户拥有独立的数据空间。

租户信息

字段说明
租户名称租户名称
描述租户描述信息
创建时间租户创建时间

租户详情

在租户详情页面可以查看:

  1. 基本信息:租户名称、描述等
  2. 租户管理员:该租户的管理员账号列表

创建租户

注意:只有主租户(ID 为 1)的管理员才能创建新租户。

  1. 进入「租户」页面
  2. 点击「创建租户」
  3. 填写租户名称和描述
  4. 点击「确认」创建

创建租户成功后,系统会自动生成租户管理员账号的凭证信息,包括:

  • 租户名称
  • 用户 ID
  • 密码

重要:租户管理员凭证只能下载一次,请妥善保存!

租户管理

多租户是当前 SaaS 云服务的关键特点之一,Passport 提供了完整的租户隔离能力。不同租户之间的数据完全隔离,互不影响。

超级租户

超级租户(ID 为 1)拥有系统最高权限,可以创建和管理其他租户。只有超级租户的管理员才能执行以下操作:

  • 创建新租户
  • 查看所有租户信息
  • 管理跨租户配置

租户信息

每个租户包含以下信息:

字段说明
租户名称租户名称
描述租户描述信息
创建时间租户创建时间

创建租户

创建租户的操作只能在超级租户下进行。

创建步骤

  1. 登录超级租户管理后台
  2. 进入「租户」页面
  3. 点击「创建租户」
  4. 填写租户名称和描述
  5. 点击「确认」创建

创建租户管理员

租户创建完成后,系统会在该租户下自动创建一个租户管理员账号。创建成功后,系统会弹出提示:

租户创建成功。租户管理员凭证仅可下载一次,请妥善保存。

点击「下载」按钮即可获取租户管理员凭证信息,包括:

  • 租户名称
  • 用户 ID
  • 密码

重要提醒

  • 凭证文件只能下载一次,请立即保存
  • 建议将凭证信息存储在安全的地方
  • 不要通过不安全的方式传输凭证

管理租户管理员

出于安全考虑,不建议多人使用同一个管理员账号。正确的操作方式是:

  1. 使用初始租户管理员账号登录
  2. 创建新的管理员账号
  3. 将新管理员账号添加到具有管理权限的群组
  4. 测试新账号权限正常后
  5. 删除或禁用初始租户管理员账号

查看租户详情

在租户列表中点击租户名称,可以进入租户详情页面查看:

  • 基本信息:租户名称、描述等
  • 租户管理员:该租户的所有管理员账号

提示:如果需要新增或移除租户管理员,请在群组中进行操作。

账号管理

Passport 基于统一的账号体系来进行身份识别和权限管控。账号体系是 Passport 最核心的部分,支撑起整个应用生态內的互联互通。

账号类型

系统支持两种类型的账号,分别对应不同的使用场景:

类型说明典型场景
个人账号真人用户使用的账号普通用户登录应用、员工使用企业系统
应用账号服务之间调用的账号微服务间 API 通信、服务认证

个人账号

个人账号用于真人用户登录系统,具有以下特点:

  • 支持邮箱登录
  • 需要密码验证
  • 可以绑定到多个群组
  • 可以分配多个权限
  • 保留登录历史记录

应用账号

应用账号用于服务之间的 API 调用认证,具有以下特点:

  • 通过 Access Key ID / Secret Access Key 认证
  • 关联到具体的应用
  • 用于服务间通信,无需人工登录
  • 支持创建和管理多个凭证
  • 不保留登录历史

账号列表

账号页面提供标签页切换功能,分别显示:

  • 个人账号:所有个人账号列表
  • 应用账号:所有应用账号列表

在账号列表中可以查看以下信息:

字段说明
用户 ID账号的唯一标识
名称用户名或应用账号名称
类型账号类型(个人账号/应用账号)
邮箱邮箱地址(仅个人账号)
所属应用关联的应用(仅应用账号)
上次登录时间最近一次登录时间
创建时间账号创建时间

创建个人账号

  1. 进入「账号」页面
  2. 切换到「个人账号」标签
  3. 点击「创建账号」
  4. 填写以下信息:
    • 用户 ID(必填)
    • 用户名(必填)
    • 邮箱(必填)
    • 密码(必填)
    • 手机号(选填)
    • 生日(选填)
  5. 点击「确认」创建

创建应用账号

  1. 进入「账号」页面
  2. 切换到「应用账号」标签
  3. 点击「创建账号」
  4. 填写以下信息:
    • 用户 ID(必填)
    • 名称(必填)
    • 所属应用(必填)
    • 描述(选填)
  5. 点击「确认」创建

账号详情

在账号列表中点击账号名称,可以进入账号详情页面。

个人账号详情

个人账号详情页面包含以下标签页:

标签页内容说明
基本信息卡用户基本信息显示用户名、邮箱、手机号等
关联群组该账号加入的所有群组可以添加或移除群组
账号权限该账号的权限列表只读,包括通过群组继承的权限
登录历史登录记录显示客户端 IP 和登录时间

应用账号详情

应用账号详情页面包含以下标签页:

标签页内容说明
基本信息卡账号基本信息显示名称、所属应用等
关联群组该账号加入的所有群组可以添加或移除群组
账号权限该账号的权限列表只读,包括通过群组继承的权限
凭证Access Key 列表可以创建和管理凭证
登录历史登录记录显示客户端 IP 和登录时间

管理凭证

应用账号需要通过 Access Key 进行认证。

创建凭证

  1. 进入应用账号详情
  2. 切换到「凭证」标签
  3. 点击「创建凭证」
  4. 系统自动生成:
    • Access Key ID
    • Secret Access Key
  5. 点击「复制」保存凭证信息

重要:Secret Access Key 只在创建时显示一次,请立即保存!

删除凭证

  1. 进入应用账号详情
  2. 切换到「凭证」标签
  3. 找到要删除的凭证
  4. 点击删除按钮
  5. 确认删除

注意:删除凭证后,使用该凭证的 API 调用将立即失败。

关联群组

将账号加入群组可以快速获得群组的权限。

添加到群组

  1. 进入账号详情
  2. 切换到「关联群组」标签
  3. 点击「添加群组」
  4. 选择要加入的群组
  5. 点击「确认」

从群组移除

  1. 进入账号详情
  2. 切换到「关联群组」标签
  3. 找到要移除的群组
  4. 点击删除按钮
  5. 确认移除

查看账号权限

账号权限标签页显示该账号拥有的所有权限,包括:

  • 直接分配给该账号的权限
  • 通过群组继承的权限

权限列表为只读,如需修改权限,请通过群组管理页面操作。

群组管理

为了降低账号管理难度,Passport 提供了账号分组能力。在企业组织中,管理员可以将相同岗位的用户账号加入到同一个群组中,只需要针对群组进行授权,群组中所有账号就可以获得相同的权限,无需单独为每个账号分别授权。

群组概述

群组是账号的集合,用于批量管理权限。通过群组,管理员可以:

  • 快速为多个账号分配相同的权限
  • 简化权限管理流程
  • 提高权限变更效率

群组信息

每个群组包含以下信息:

字段说明
群组名称群组的唯一名称
描述群组描述信息
创建时间群组创建时间
更新时间群组最后更新时间

创建群组

  1. 进入「群组」页面
  2. 点击「创建群组」
  3. 填写以下信息:
    • 群组名称(必填)
    • 描述(选填)
  4. 点击「确认」创建

群组详情

在群组列表中点击群组名称,可以进入群组详情页面。群组详情包含以下标签页:

标签页内容说明
基本信息卡群组基本信息显示群组名称、描述等
群组成员该群组包含的所有账号可以添加或移除成员
群组权限该群组拥有的权限可以添加或移除权限

管理群组成员

将账号添加到群组后,该账号会自动获得群组的所有权限。

添加成员

  1. 进入群组详情
  2. 切换到「群组成员」标签
  3. 点击「添加成员」
  4. 选择要添加的账号(支持多选)
  5. 点击「确认」

移除成员

  1. 进入群组详情
  2. 切换到「群组成员」标签
  3. 找到要移除的账号
  4. 点击删除按钮
  5. 确认移除

注意:移除成员后,该账号将失去群组的所有权限。

管理群组权限

为群组添加权限后,群组中的所有账号都会获得这些权限。

添加权限

  1. 进入群组详情
  2. 切换到「群组权限」标签
  3. 点击「添加权限」
  4. 选择要添加的权限(支持多选)
  5. 点击「确认」

移除权限

  1. 进入群组详情
  2. 切换到「群组权限」标签
  3. 找到要移除的权限
  4. 点击删除按钮
  5. 确认移除

注意:移除权限后,群组中的所有账号都会失去该权限。

权限继承

群组的权限会自动继承给群组中的所有账号。当群组权限发生变化时:

  • 添加权限:群组中所有账号立即获得新权限
  • 移除权限:群组中所有账号立即失去该权限

账号的实际权限是以下权限的并集:

  • 直接分配给账号的权限
  • 账号所属群组的权限

群组使用建议

按部门/组织架构分组

  • 开发部群组
  • 产品部群组
  • 运营部群组
  • ...

按岗位角色分组

  • 管理员群组
  • 操作员群组
  • 只读用户群组
  • ...

按项目分组

  • 项目 A 群组
  • 项目 B 群组
  • ...

注意事项

  • 一个账号可以加入多个群组
  • 群组权限变化会立即生效
  • 建议定期审查群组成员和权限配置
  • 不再使用的群组建议删除或禁用

权限管理

权限是 API 接口的集合,表示一组操作能力。用户想要正常使用某个服务,必须先拥有该服务的相应权限。

权限概述

权限是连接账号和 API 的桥梁。通过权限,管理员可以:

  • 将多个 API 组合成一个权限单元
  • 将权限分配给账号或群组
  • 实现细粒度的访问控制

一般服务至少会定义三个级别的权限:

权限级别风险等级对应角色描述
管理员权限高风险管理员拥有系统的所有操作权限
操作者权限中风险操作者拥有大部分操作权限,但无法进行系统配置
只读权限低风险只读用户仅拥有查询权限

权限信息

每个权限包含以下信息:

字段说明
权限名称权限的唯一名称
描述权限描述信息
所属应用权限所属的应用
接口数量该权限包含的 API 数量
创建时间权限创建时间

权限列表

在权限列表中可以查看所有已创建的权限,包括:

字段说明
权限名称点击可进入详情页
所属应用权限所属的应用名称
接口数量该权限包含的 API 数量
创建时间权限创建时间

创建权限

  1. 进入「权限」页面
  2. 点击「创建权限」
  3. 填写以下信息:
    • 权限名称(必填)
    • 所属应用(必填,从下拉列表选择)
    • 描述(选填)
  4. 点击「确认」创建

创建权限后,可以在权限详情中添加关联的 API。

权限详情

在权限列表中点击权限名称,可以进入权限详情页面。权限详情包含以下标签页:

标签页内容说明
基本信息卡权限基本信息显示权限名称、描述、所属应用等
关联接口该权限包含的所有 API可以添加或移除接口
授权账号直接分配了该权限的账号只读,不包括通过群组继承的

管理关联接口

将 API 添加到权限后,拥有该权限的账号/群组就可以访问这些 API。

添加接口

  1. 进入权限详情
  2. 切换到「关联接口」标签
  3. 点击「添加接口」
  4. 选择要添加的 API(支持多选)
  5. 点击「确认」

移除接口

  1. 进入权限详情
  2. 切换到「关联接口」标签
  3. 找到要移除的 API
  4. 点击删除按钮
  5. 确认移除

注意:移除接口后,拥有该权限的账号将无法访问该接口。

查看授权账号

授权账号标签页显示直接分配了该权限的所有账号。

注意:此列表只显示直接分配了权限的账号,不包括通过群组继承获得权限的账号。如需查看所有拥有该权限的账号,请分别查看每个群组的成员列表。

权限设计建议

按功能模块划分

  • 用户管理权限
  • 产品管理权限
  • 订单管理权限
  • ...

按操作类型划分

  • 查看权限
  • 编辑权限
  • 删除权限
  • ...

按风险等级划分

  • 管理员权限(高风险)
  • 操作者权限(中风险)
  • 只读权限(低风险)

组合方式

实际应用中,通常会采用组合方式,例如:

权限名称描述包含 API
user-admin用户管理(管理员)用户查询、创建、编辑、删除的所有 API
user-operator用户管理(操作者)用户查询、创建、编辑的 API
user-reader用户管理(只读)仅用户查询 API

注意事项

  • 权限名称应具有描述性,便于识别
  • 建议为每个应用至少创建三个权限级别
  • 定期审查权限配置,确保安全性
  • 避免创建过于细碎的权限,增加管理复杂度

应用管理

应用是权限管理的容器,每个应用都有自己的 API 和权限。应用管理允许开发者在 Passport 平台上注册自己的应用,并定义应用的 API 接口清单和权限体系。

应用概述

应用是指需要接入 Passport 认证鉴权的业务系统或服务。每个应用在 Passport 中都有独立的:

  • 应用 ID(App Key):应用的唯一标识
  • API 列表:应用暴露的所有接口
  • 权限列表:应用定义的权限
  • 应用账号:用于服务间调用的账号

应用信息

每个应用包含以下信息:

字段说明
应用 ID(App Key)应用的唯一标识,创建时自动生成
应用名称应用名称
描述应用描述信息
创建时间应用创建时间

应用列表

在应用列表中可以查看所有已注册的应用:

字段说明
应用 ID点击可进入详情页
应用名称应用名称
描述应用描述信息
创建时间应用创建时间

创建应用

  1. 进入「应用」页面
  2. 点击「创建应用」
  3. 填写以下信息:
    • 应用名称(必填)
    • 描述(选填)
  4. 点击「确认」创建

创建应用成功后,系统会自动生成应用 ID(App Key),用于唯一标识该应用。

应用详情

在应用列表中点击应用 ID,可以进入应用详情页面。应用详情包含以下标签页:

标签页内容说明
基本信息卡应用基本信息显示应用 ID、名称、描述等
权限该应用下创建的所有权限只读,列出权限名称和接口数量
接口该应用下定义的所有 API可以添加、编辑、删除接口

管理接口

接口是权限控制的基本单位,每个接口代表一个具体的 API 端点。

创建接口

  1. 进入应用详情
  2. 切换到「接口」标签
  3. 点击「创建接口」
  4. 填写以下信息:
    • 接口名称(必填)
    • 请求路径(必填)
    • 请求方法(必填,支持 GET/POST/PUT/DELETE)
    • 描述(选填)
  5. 点击「确认」创建

编辑接口

  1. 进入应用详情
  2. 切换到「接口」标签
  3. 找到要编辑的接口
  4. 点击编辑按钮
  5. 修改接口信息
  6. 点击「确认」保存

删除接口

  1. 进入应用详情
  2. 切换到「接口」标签
  3. 找到要删除的接口
  4. 点击删除按钮
  5. 确认删除

注意:删除接口后,该接口将从所有关联的权限中移除。

导出接口列表

应用管理支持导出接口列表,方便在开发过程中使用。

  1. 进入应用详情
  2. 切换到「接口」标签
  3. 点击「导出」按钮
  4. 选择导出格式
  5. 保存导出文件

接口信息

每个接口包含以下信息:

字段说明
接口名称接口的名称
请求路径接口的请求路径,支持通配符(如 /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

创建应用账号

应用需要账号来进行服务间认证。

创建应用账号

  1. 进入「账号」页面
  2. 切换到「应用账号」标签
  3. 点击「创建账号」
  4. 填写以下信息:
    • 用户 ID(必填)
    • 名称(必填)
    • 所属应用(必填,选择该应用)
    • 描述(选填)
  5. 点击「确认」创建

管理凭证

创建应用账号后,需要创建 Access Key 凭证:

  1. 进入应用账号详情
  2. 切换到「凭证」标签
  3. 点击「创建凭证」
  4. 保存生成的 Access Key ID 和 Secret Access Key

应用集成流程

完成应用注册后,按照以下步骤集成 Passport:

  1. 创建应用:在管理后台创建应用,获取应用 ID
  2. 定义接口:将应用的 API 接口清单注册到应用中
  3. 创建权限:定义应用的权限级别(管理员、操作者、只读等)
  4. 关联接口:将接口关联到对应的权限
  5. 创建应用账号:创建应用服务账号,获取 Access Key
  6. 引入 SDK:在应用代码中引入 Passport SDK
  7. 配置 SDK:配置应用 ID、Access Key、公钥等信息
  8. 测试验证:测试认证鉴权功能是否正常

详细的 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. 创建应用

  1. 登录 Passport 管理后台
  2. 进入「应用」页面
  3. 点击「创建应用」

  1. 填写应用信息:
    • 应用名称(必填)
    • 描述(选填)
  2. 点击「确认」创建

创建成功后,系统会自动生成应用 ID,用于唯一标识该应用。

已知限制:当前版本服务端在创建应用时不会自动生成 App Key,该字段需要另行配置。详见「高阶操作」的应用管理章节。

2. 创建应用账号

应用需要账号来进行服务间认证(如调用 Passport 公开接口)。

  1. 进入「账号」页面
  2. 切换到「应用账号」标签
  3. 点击「创建账号」
  4. 填写以下信息:
    • 用户 ID(必填)
    • 名称(必填)
    • 所属应用(必填,选择刚创建的应用)
    • 描述(选填)
  5. 点击「确认」创建

3. 获取 Access Key

应用账号创建后,需要获取凭证用于 API 调用。

  1. 进入应用账号详情
  2. 切换到「凭证」标签
  3. 点击「创建凭证」
  4. 系统自动生成:
    • Access Key ID
    • Secret Access Key
  5. 保存凭证信息

重要:Secret Access Key 只在创建时显示一次,请立即保存!

4. 定义 API 接口

将应用的 API 接口清单注册到 Passport 平台。

  1. 进入应用详情
  2. 切换到「接口」标签
  3. 点击「创建接口」
  4. 填写接口信息:
    • 接口名称(必填)
    • 请求路径(必填,如 /api/user/*
    • 请求方法(必填,支持 GET/POST/PUT/DELETE)
    • 描述(选填)
  5. 点击「确认」创建

重复以上步骤,将所有接口注册到平台。

5. 导出接口列表

应用管理支持导出接口列表,方便在开发过程中使用。

  1. 进入应用详情
  2. 切换到「接口」标签
  3. 点击「导出」按钮
  4. 保存导出的文件

导出结果为 Excel 文件(.xlsx),文件名格式为 API-yyyyMMddHHmmss.xlsx,例如 API-20260830143022.xlsx。当前仅支持这一种格式。

6. 创建权限

定义应用的权限级别。

  1. 进入「权限」页面
  2. 点击「创建权限」
  3. 填写以下信息:
    • 权限名称(必填)
    • 所属应用(必填,选择刚创建的应用)
    • 描述(选填)
  4. 点击「确认」创建

建议为每个应用创建至少三个权限级别:

权限级别风险等级对应角色描述
管理员权限高风险管理员拥有应用的所有操作权限
操作者权限中风险操作者拥有大部分操作权限
只读权限低风险只读用户仅拥有查询权限

7. 关联接口到权限

将 API 接口关联到对应的权限。

  1. 进入权限详情
  2. 切换到「关联接口」标签
  3. 点击「添加接口」
  4. 选择要添加的 API(支持多选)
  5. 点击「确认」

重复以上步骤,将所有接口关联到对应的权限。

信息汇总

完成服务发布后,您将获得以下信息:

信息说明获取方式
应用 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 通过以下机制实现认证鉴权:

  1. 认证拦截:通过 AuthFilter 拦截所有请求,验证 Token 有效性
  2. Token 验证:使用公钥验证 JWT Token 签名,解析用户信息
  3. 权限控制:从本地缓存的 API 和权限配置中,验证用户是否有访问权限
  4. 缓存同步:通过定时任务从 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-urlhttps://passport.vancone.comPassport 服务地址
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.algorithmES256Token 签名算法,当前仅支持 ES256
passport.access-control.enabledtrue是否启用权限控制
passport.cache.sync-period-seconds60缓存同步周期(秒)
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 属性

属性类型说明
idString账户 ID
userIdString用户 ID
nameString用户名称
typeString账户类型
tenantIdString租户 ID
permissionIdsList权限 ID 列表

认证流程说明

  1. 请求到达:客户端发起请求,SDK 的 AuthFilter 拦截请求

  2. Token 获取:SDK 按以下顺序获取 Token:

    • 从 HTTP Header passport-token 获取
    • 从 Cookie passport_token 获取
  3. Token 验证:使用配置的公钥验证 Token 签名

  4. 权限验证(如果启用):

    • 从 Token 中提取用户的权限 ID 列表
    • 从本地缓存中匹配请求的 API
    • 验证用户权限是否包含该 API
  5. 请求处理:验证通过后,将用户信息存入 ThreadLocal,继续处理请求

  6. 清理:请求结束后,自动清理 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-keyprivate-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:

  1. 登录 Passport 管理后台
  2. 进入「应用管理」
  3. 创建新应用或选择现有应用
  4. 查看应用的 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-godevelop 分支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/gingithub.com/spf13/vipergithub.com/golang-jwt/jwt/v5。要求 Go 1.21.3 及以上。

Step 2:修改配置文件

config.yamlconfig.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-urlhttps://passport.vancone.comPassport 平台地址,SDK 调用平台接口时的前缀
token.public-key-用于校验 Token 的公钥(Base64 编码的 PKIX 公钥)
authentication.enabledtrue是否开启登录认证;置为 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 结构体定义:

字段类型说明
tenantIdstring租户 ID
accountIdstring账号 ID
userIdstring用户 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,流程为:

  1. POST {base-url}/api/passport/service/v1/token/signature,请求体 {"accessKeyId": "...", "secretAccessKey": "..."},返回 {"timestamp": "...", "signature": "..."}
  2. POST {base-url}/api/passport/service/v1/token,请求体 {"accessKeyId": "...", "timestamp": "...", "signature": "..."},返回 Token 字符串

风险提示:若 ak / sk 配置错误或应用账号无权限,平台返回的 datanull,此时 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 请求。authtrue 时自动在 passport-token 请求头中携带 ApplyToken() 获取的 Token。出错时返回 nil
util.RequestWithAuth(uri, method, body string) []byte等价于 Request(uri, method, body, true)

中间件说明

middleware.AuthMiddleware 的处理流程:

  1. 开关判断:若 authentication.enabledfalse,直接放行所有请求。
  2. 白名单匹配:请求路径命中 authentication.uri-allowlist 中的任一模式时放行,不做 Token 校验。
  3. 读取 Token:优先从 Cookie passport_token 读取;Cookie 为空时,从请求头 passport-token 读取。
  4. 校验 Token:使用配置中的公钥校验 ES256 签名,并校验有效期。
  5. 注入用户信息:校验通过后,将账号信息写入 Gin Context;校验失败则中断请求并返回 HTTP 401

Token 的传递方式(前后端对接时需要对齐):

位置名称
Cookiepassport_token
请求头passport-token

鉴权失败的响应:当前版本中间件调用 AbortWithStatus(401) 中断请求,响应体为空。如需与平台统一的错误格式({"code": 11002, "message": "Not authorized"})保持一致,请在业务侧自行追加一个错误处理中间件构造响应体。

Context 中可用的信息

通过中间件后,可以在 Handler 中通过 Gin Context 获取以下信息:

Key 常量Key 实际值类型说明
constant.TokenKeyAccountIdacidstring账号 ID
constant.TokenKeyTenantIdtidstring租户 ID
constant.TokenKeyUserIduidstring用户 ID(登录名)
constant.AccountInfoaccountInfomodel.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

注意事项

  1. 公钥获取:公钥为 Base64 编码的 PKIX 公钥(ES256)。请从 Passport 部署方获取,并妥善保管;公钥变更会导致所有 Token 校验失败。
  2. 安装版本:务必指定 @develop 或正式版本号,不带版本约束的 go get 会安装到 API 不兼容的旧版本。
  3. 初始化顺序config.Init() 必须在注册 middleware.AuthMiddleware 之前调用,否则公钥与白名单均无法加载。
  4. URI 白名单:不需要认证的接口(如健康检查、公开查询)应添加到 authentication.uri-allowlist
  5. 算法支持:当前版本仅支持 ES256,非 ECDSA 签名的 Token 会被直接拒绝。
  6. 权限校验:尚未实现,不要在业务中依赖 access-control 配置或 PermissionIds 字段。

SDK 架构说明

模块文件路径说明
配置管理pkg/config/config.go使用 Viper 读取配置,提供默认值
中间件pkg/middleware/middleware.goToken 验证、用户信息注入、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.goAccountInfo 结构体
常量定义pkg/constant/constant.goCookie Key、Header Key、Token Key 定义

导出函数一览

函数签名说明
config.InitInit(viper *viper.Viper)初始化 SDK 配置
middleware.AuthMiddlewarefunc(ctx *gin.Context)认证中间件
middleware.Authenticatefunc(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 SDKGo SDK
框架Spring BootGin
配置方式@ConfigurationProperties + @EnableConfigurationPropertiesViper + YAML 配置文件
中间件Servlet FilterGin Middleware
Token 验证JJWTgolang-jwt/jwt
Token 传递Cookie + HeaderCookie passport_token + Header passport-token
Token 算法ES256ES256
路径匹配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:

方式名称
Cookiepassport_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出现场景
2000成功
200100011000540014006登录失败、找回密码失败。业务错误仍返回 200,必须解析 body 中的 code 判断
200 / 500-1服务端异常、参数绑定失败等兜底错误
40111002Token 缺失或无效
403403越权(例如尝试更新他人账号)
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):

参数类型必填说明
userIdstring登录名。与 email 二选一,二者同时为空时按空账号处理
emailstring邮箱。userId 为空时作为登录标识
passwordstring密码明文,服务端以 BCrypt 比对
captchaTokenstring滑块验证码校验通过后返回的票据
tenantIdstring租户 ID

响应

{
  "code": 0,
  "message": "success",
  "data": {
    "token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9...",
    "username": "admin"
  }
}

响应中只有 tokenusername 两个字段。username 取账号的 name,未设置 name 时回退为 userId

业务结果:登录成功时同时下发 passport_tokenpassport_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_tokenpassport_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 记录客户端类型。

请求体:

参数类型必填说明
userIdstring登录名。与 email 二选一
emailstring邮箱
passwordstring密码明文
captchaTokenstring滑块验证码票据(见 8.3),App 端同样必须过滑块
tenantIdstring租户 ID
clientTypestring客户端类型: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

请求体

参数类型必填说明
accessKeyIdstring应用账号的 Access Key ID
secretAccessKeystring应用账号的 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

请求体

参数类型必填说明
accessKeyIdstringAccess Key ID
timestampstring上一步返回的毫秒时间戳
signaturestring上一步返回的签名

响应dataToken 字符串(不是对象)。

{
  "code": 0,
  "message": "success",
  "data": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9..."
}

签名校验失败时返回 HTTP 500、code-1messagesignature validation failed

2.3 验证 Token

POST /api/passport/service/v1/token/validate

请求体

参数类型必填说明
tokenstring要验证的 Token

响应data布尔值

{
  "code": 0,
  "message": "success",
  "data": true
}

2.4 获取 Token 剩余有效期

POST /api/passport/service/v1/token/expiration

请求体

参数类型必填说明
tokenstring要查询的 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 在本次调用中被消费,立即作废。

请求体:

参数类型必填说明
refreshTokenstring1.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 字段。
  • lastLoginTimebirthDayapplicationName 为派生字段,当前实现不会填充,响应中不会出现。生日信息请通过「用户资料」接口获取(见 4.1,字段名为 birthday)。

3.2 创建账号(注册)

POST /api/passport/service/v1/account

该接口免 Token 校验。

请求体

参数类型必填说明
userIdstring登录名
typestring账号类型:PERSONALSERVICE
namestring账号名称
passwordstring密码。个人账号建议必填
emailstring邮箱地址
phonestring手机号码
applicationIdstring所属应用 ID,仅应用账号需要

响应:与 3.1 相同的账号对象。

说明:当前版本注册不需要邮箱验证码,注册完成即可登录,账号没有「待激活」状态。密码复杂度仅由前端校验,服务端未做强制约束,接入方如需约束请自行在业务侧实现。

3.3 更新账号

PUT /api/passport/service/v1/account

需要携带 Token。

请求体

参数类型必填说明
idstring账号 ID,必须与 Token 中的 acid 一致,否则返回 403
namestring账号名称
emailstring邮箱地址,找回密码时使用
phonestring手机号码

响应

{
  "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更新时间

资料中不包含 emailphone,这两个字段属于账号(Account)而非资料(Profile)。

4.2 更新用户资料

PUT /api/passport/service/v1/account-profile

需要携带 Token。

请求体

参数类型必填说明
namestring姓名
genderstring性别:MALE / FEMALE / OTHERS
birthdaystring生日(格式:YYYY-MM-DD)
biostring个人简介

响应

{
  "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 上传。

请求参数

参数类型必填说明
filefile头像文件。仅支持 .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。

请求参数

参数类型必填说明
pageNoint页码,默认 1
pageSizeint每页数量,默认 10
searchstring搜索关键字
accountIdstring指定账号 ID 查询

响应

{
  "code": 0,
  "message": "success",
  "data": {
    "list": [
      {
        "id": "1234567890",
        "userId": "user123",
        "name": "张三"
      }
    ],
    "pageNo": 1,
    "pageSize": 10,
    "totalCount": 100,
    "totalPage": 10
  }
}

分页查询仅返回 iduserIdname 三个字段,不包含邮箱、手机号等信息。如需完整账号信息,请先按 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

请求参数

参数类型必填说明
emailstring邮箱地址

响应datanull,验证码通过邮件发送。

{
  "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。

请求参数

参数类型必填说明
pointstring用户拖动滑块的落点坐标,格式 "x,y",例如 "118,45"
keystring8.2 返回的 key

响应

{
  "code": 0,
  "message": "success",
  "data": {
    "captchaToken": "captcha:token:xxxxxxxx",
    "ok": true
  }
}

说明:校验容差为 4 像素。okfalse 表示校验未通过,此时 captchaToken 为空。校验通过后返回的 captchaToken 用于登录(1.1)与找回密码(8.4),且为一次性凭证。


Forgot Password 模块

修改密码需通过以下三段式流程完成,该模块全部接口免 Token 校验。流程起点仍需先过滑块验证码。

9.1 发送验证码

POST /api/passport/service/v1/account/forgot-password/send-code

请求体

参数类型必填说明
captchaTokenstring滑块验证码票据(见 8.3)
emailstring注册时使用的邮箱

响应

{
  "code": 0,
  "message": "success"
}

失败时返回 HTTP 200 与对应的业务码(见「错误码」),例如 4001 Email not registered

9.2 校验验证码

POST /api/passport/service/v1/account/forgot-password/verify-code

请求体

参数类型必填说明
emailstring邮箱
codestring邮件中的验证码

响应

{
  "code": 0,
  "message": "success",
  "data": {
    "resetToken": "xxxxxxxx"
  }
}

9.3 重置密码

POST /api/passport/service/v1/account/forgot-password/reset

请求体

参数类型必填说明
emailstring邮箱
resetTokenstring8.5 返回的 resetToken
newPasswordstring新密码

响应

{
  "code": 0,
  "message": "success"
}

完整流程

  1. 调用 8.2 获取滑块验证码素材
  2. 调用 8.3 提交滑块位置,换取 captchaToken
  3. 调用 9.1(携带 captchaToken 与邮箱)发送邮件验证码
  4. 调用 9.2(携带邮箱与邮件验证码)换取 resetToken
  5. 调用 9.3(携带邮箱、resetToken、新密码)完成重置

错误码

通用

错误码HTTP 状态码说明
0200成功
-1500服务端异常或参数绑定失败,message 为具体错误描述
403403越权操作
11002401Token 缺失或无效({"code":11002,"message":"Not authorized"}

登录(Login)

错误码说明
10001Account not found(账号不存在)
10002Incorrect password(密码错误)
10003Account locked due to too many failed attempts(失败次数超限,账号已锁定)
10004Account is disabled(账号已禁用)
10005Captcha verification failed(滑块验证码校验失败)

以上错误码均伴随 HTTP 200 返回,请通过 body 中的 code 判断,不要只看 HTTP 状态码。

找回密码(Forgot Password)

错误码说明
4001Email not registered(邮箱未注册)
4002Invalid verification code(验证码错误)
4003Verification code expired(验证码已过期)
4004Invalid reset token(resetToken 无效)
4005Too many attempts(尝试次数过多)
4006Captcha verification failed(滑块验证码校验失败)
5001Unknown error(兜底错误)

同样伴随 HTTP 200 返回。

管理端(passport-admin)

管理端服务使用独立的错误码空间:

错误码说明
10001Forbidden(无权限)
10002资源 ID 重复
10004参数非法

认证流程

个人账号登录流程

  1. 调用「生成滑块验证码」获取验证码素材
  2. 调用「校验滑块验证码」提交滑块位置,换取 captchaToken
  3. 调用「用户登录」,携带 captchaToken、登录名、密码
  4. 保存返回的 token,后续请求在 passport-token 请求头或 passport_token Cookie 中携带

扫码登录流程

Web 端与扫码设备端的完整接入步骤见「扫码登录接入」的「接入清单」。

App 登录与续期流程

  1. 调用「生成滑块验证码」+「校验滑块验证码」换取 captchaToken
  2. 调用「App 登录」(1.3),安全保存返回的 tokenrefreshToken
  3. access token 过期(或收到 401)时,调用「刷新 Token」(2.5)静默续期;刷新失败则回登录页
  4. 登出时携带 refreshToken 调用 DELETE /login,服务端吊销后清除本地存储

应用账号换取 Token 流程

  1. 调用「生成签名」,传入 accessKeyIdsecretAccessKey,获得 signaturetimestamp
  2. 调用「生成 Token」,传入 accessKeyIdtimestampsignature
  3. 保存返回的 Token 字符串,后续请求在 passport-token 请求头中携带
  4. Token 有效期 24 小时且不支持续期,过期后重新执行本流程(SDK 已内置该流程与缓存,参见「SDK 集成」章节)

权限判断

Token 的 pids 声明中携带了账号被授予的权限 ID 列表。接入方有两种做法:

  1. 直接解析 JWT 的 pids 声明(需持有公钥校验签名)
  2. 调用「同步权限列表」接口获取权限定义,与 pids 比对

注意:Go SDK 当前版本不会解析 pidsAccountInfo.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 Cookiedata 中附带 tokenusername;且会话被本次轮询原子消费,后续再查询一律返回 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 状态码codemessage
会话不存在或已过期(scan / confirm)500-1qrcode login session not found or expired
会话状态非法流转(如确认已被消费的会话)500-1invalid qrcode login session state
scan / confirm 未携带有效 Token40111002Not authorized
创建会话服务端异常(如 Redis 不可用)500-1具体错误描述

查询状态接口不返回错误码:会话过期体现在 status: expired 中,HTTP 状态码仍为 200。

安全要点

  1. authCode 一次性有效:确认后被 Web 端轮询取走即从服务端删除,防重放
  2. scan / confirm 必须携带扫码设备自身的有效登录态,未登录设备无法确认
  3. 会话有效期仅 120 秒,过期必须重新创建,避免长期挂起的待确认会话
  4. 登录成功会写入登录历史,loginMethodQR_CODE(见「公开接口」的登录历史一节)

接入清单

Web 端(登录页):

  1. 调用「创建扫码会话」,将 authCode 按约定格式渲染为二维码
  2. 每 2 秒调用「查询扫码状态」,展示 pending / scanned / expired
  3. 轮询到 confirmed 即登录完成:服务端已在该响应中下发 Cookie
  4. 会话过期后重新执行第 1 步

扫码设备端(App):

  1. 扫码解析出 authCode
  2. 调用「上报已扫码」(需要设备自身的有效 Token)
  3. 用户确认后调用「确认登录」完成登录

服务与组件清单

Passport 由以下服务与组件构成。

后端服务

服务仓库目录类型默认端口说明
passport-servicepassport/passport-service后端(Go / Gin)10010认证服务。处理注册、登录、Token 签发与校验、账号资料、验证码、找回密码、同步接口
passport-adminpassport/passport-admin后端(Go / Gin)10011管理服务。提供租户、账号、群组、权限、应用、应用 API 的管理接口

前端应用

应用仓库目录技术栈说明
passport-webpassport/passport-webVue 3 + TypeScript用户界面,提供注册、登录、个人中心
passport-admin-webpassport/passport-admin-webVue 3 + TypeScript管理界面,提供租户、账号、群组、权限、应用的管理页面

SDK

SDK位置适用框架说明
Java SDKpassport/passport-sdk-javaSpring Boot通过 Servlet Filter 实现认证鉴权拦截,当前版本 0.1.4
Go SDKvancone-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开发侧设计文档