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
权限校验支持尚未实现