Logto SDK不支持移动端直连,必须通过Go后端代理完成OIDC授权码流程:移动端跳转至后端中间页发起登录,后端调用logto-go交换token并签发短期session JWT,移动端凭此JWT访问业务API,后端中间件校验JWT而非Logto token。

Logto SDK不支持移动端直连,必须走后端代理
Logto 的 logto-js 和官方 SDK 默认面向 Web 浏览器设计,依赖 localStorage、document.cookie 或重定向流程,移动端(iOS/Android 原生 App)无法安全存储敏感凭证,也不能可靠拦截 302 跳转。直接在移动端调用 Logto OIDC 端点(如 /oidc/authz)会触发 CORS 错误或 token 泄露风险——这不是 Golang 配置问题,而是架构前提错误。
正确路径是:移动端只与你的 Go 后端通信;Go 服务作为 OIDC Relying Party,代表客户端完成授权码交换、token 刷新、用户信息获取;移动端仅传递临时授权码或 session ID。
- 移动端发起登录时,跳转到你的 Go 服务提供的中间页(如
/auth/start),由 Go 构造标准 OIDC 授权请求并重定向至 Logto - Logto 回调到你的
/auth/callback(需在 Logto 控制台注册为 Valid redirect URI),Go 完成 code → token 换取,并生成短期 session token(如 JWT)返回给 App - 后续所有 API 请求携带该 session token,由 Go 中间件校验其有效性及绑定的用户身份
用 logto-go SDK 实现 OIDC 授权码流程
logto-go 是 Logto 官方维护的 Go 客户端 SDK,但仅封装了 OIDC 底层交互,不提供开箱即用的 HTTP 中间件。你需要手动集成授权码流程关键步骤。
核心依赖:
立即学习“go语言免费学习笔记(深入)”;
- 使用
logto-go初始化 client:logto.NewClient(&logto.Config{Endpoint: "https://your-logto-domain.com", AppID: "your-app-id", AppSecret: "your-app-secret"}) - 回调 endpoint 必须启用 HTTPS,且域名与 Logto 控制台中注册的
Redirect URIs完全一致(含末尾斜杠) - 务必校验回调中的
state参数防 CSRF,建议用加密随机字符串 + 存入短期 session(如 Redis)
示例片段(简化):
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
// /auth/callback handler
func callbackHandler(w http.ResponseWriter, r *http.Request) {
code := r.URL.Query().Get("code")
state := r.URL.Query().Get("state")
// 校验 state 是否匹配 session 中存储的值
if !validateState(state) {
http.Error(w, "invalid state", http.StatusBadRequest)
return
}
token, err := logtoClient.ExchangeAuthorizationCode(r.Context(), code)
if err != nil {
http.Error(w, "exchange failed", http.StatusInternalServerError)
return
}
// 解析 ID Token 获取 user_id,签发你自己的短期访问 token
claims := parseIDToken(token.IDToken)
appToken := issueAppSession(claims.Subject)
http.SetCookie(w, &http.Cookie{
Name: "session_token",
Value: appToken,
Path: "/",
MaxAge: 3600,
HttpOnly: true,
Secure: true, // 生产环境必须开启
})
}
鉴权中间件需分离「认证」与「授权」逻辑
不要把 Logto 的 token 直接当 API 凭据用。Logto 发放的 access token 是给你的 Go 服务调用 Logto API(如 /api/users/{id})用的,不是给移动端调用你业务接口的。
推荐做法:中间件只验证你签发的 session_token(JWT),从中提取 sub(用户 ID)和 exp,再根据业务需求做 RBAC 或 ABAC 决策。
- JWT secret 必须从环境变量加载,禁止硬编码;建议轮换周期 ≤7 天
- 若需实时吊销(如用户登出),需维护一个 Redis 黑名单(key:
blacklist:{jti}),在中间件中检查jti是否存在 - 避免在中间件里调用 Logto API 验证 token——这会拖慢所有请求;Logto token 只在登录/刷新时验证一次
中间件示意:
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("session_token")
if err != nil {
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
}
claims := validateAppJWT(cookie.Value) // 仅校验签名+过期,不查 Logto
if claims == nil {
http.Error(w, "invalid session", http.StatusUnauthorized)
return
}
// 注入用户上下文,供后续 handler 使用
ctx := context.WithValue(r.Context(), "user_id", claims.Subject)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
移动端传参方式影响 Go 服务的安全边界
移动端如何传 session token?不同方式决定你中间件的校验策略和攻击面。
- Header 方式(推荐):
Authorization: Bearer <your-app-jwt>—— 不受 Cookie 同源限制,可跨域,且避免 CSRF;Go 中间件从r.Header.Get("Authorization")提取 - Query 参数(不推荐):易被日志、代理、CDN 缓存泄露;必须禁用 access log 记录 query string
- Cookie 方式:需确保 Go 服务与移动端 WebView 或原生网络库同域(通常做不到),且必须设
Secure+HttpOnly+SameSite=Strict
无论哪种方式,都必须在中间件开头校验 token 是否为空、格式是否合法(如 Bearer 前缀)、是否被篡改。Logto 本身不解决移动端传输层安全,这部分完全由你的 Go 服务兜底。
最常被忽略的是:Logto 的 access_token 有效期通常很短(默认 1 小时),而移动端 session token 应该更短(15–30 分钟),且必须实现独立的 refresh 流程——不能复用 Logto 的 refresh token,因为那需要暴露 app_secret 到移动端。

















