feat(identity): 收敛 AI Gateway 统一认证入口
Web 登录页合并为单一统一认证入口,未指定上下文时由认证中心在登录后决策。继续接受旧客户端显式传入 platform 或 tenant,并保持回调上下文及 tenant_hint 的绑定校验。同步更新 OpenAPI 产物。\n\n验证:Go 全量测试与 go vet 通过;Web lint、141 项 Vitest 和生产构建通过;本地 platform.admin 登录及管理工作台访问通过。
This commit is contained in:
@@ -36,7 +36,7 @@ const (
|
||||
// @Description Gateway 生成 state、nonce 和 PKCE S256 参数,并跳转认证中心;浏览器不接触 Token。
|
||||
// @Tags auth
|
||||
// @Param returnTo query string false "登录后返回的站内相对路径"
|
||||
// @Param contextType query string true "显式登录上下文:platform 或 tenant"
|
||||
// @Param contextType query string false "兼容旧入口的显式登录上下文:platform 或 tenant;省略时由认证中心选择"
|
||||
// @Param tenantHint query string false "Tenant 上下文可选的稳定 Tenant UUID"
|
||||
// @Success 303
|
||||
// @Failure 400 {object} ErrorEnvelope
|
||||
@@ -54,7 +54,8 @@ func (s *Server) startOIDCLogin(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
contextType := strings.TrimSpace(r.URL.Query().Get("contextType"))
|
||||
tenantHint := strings.TrimSpace(r.URL.Query().Get("tenantHint"))
|
||||
validContext := contextType == "tenant" ||
|
||||
validContext := contextType == "" ||
|
||||
contextType == "tenant" ||
|
||||
contextType == "platform" &&
|
||||
runtime.Revision.TenantMode == "multi_tenant"
|
||||
validTenantHint := tenantHint == "" ||
|
||||
@@ -141,9 +142,7 @@ func (s *Server) completeOIDCLogin(w http.ResponseWriter, r *http.Request) {
|
||||
s.writeOIDCTokenFailure(w, r, "ACCESS_TOKEN_INVALID", auth.OIDCValidationCategory(err), "认证中心访问令牌校验失败")
|
||||
return
|
||||
}
|
||||
if identity.ContextType != transaction.ContextType ||
|
||||
transaction.TenantHint != "" &&
|
||||
identity.TenantID != transaction.TenantHint {
|
||||
if !oidcLoginContextMatches(transaction, identity) {
|
||||
s.writeOIDCTokenFailure(
|
||||
w, r, "ACCESS_TOKEN_CONTEXT_MISMATCH",
|
||||
"STABLE_IDENTITY_CLAIMS_INVALID",
|
||||
@@ -190,6 +189,17 @@ func (s *Server) completeOIDCLogin(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, oidcReturnLocation(runtime.Revision.WebBaseURL, transaction.ReturnTo), http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func oidcLoginContextMatches(
|
||||
transaction oidcsession.LoginTransaction,
|
||||
identity *auth.User,
|
||||
) bool {
|
||||
return identity != nil &&
|
||||
(transaction.ContextType == "" ||
|
||||
identity.ContextType == transaction.ContextType) &&
|
||||
(transaction.TenantHint == "" ||
|
||||
identity.TenantID == transaction.TenantHint)
|
||||
}
|
||||
|
||||
func (s *Server) replaceOIDCBrowserSession(
|
||||
ctx context.Context,
|
||||
r *http.Request,
|
||||
|
||||
Reference in New Issue
Block a user