0.11.2: 旗舰版第三轮完善(通用聊天/企微钉钉飞书扫码登录/个人安全策略)

- 门户通用聊天:选择已批准模型直接对话,审批通过后自动开通用户级运行时
  API Key(加密落库,限额取批准值),聊天经受管网关统一认证/限流/配额/审计;
  会话哈希链完整性 + busy 租约防并发,失败不落库。
- 扫码登录:identity_providers 扩展 wecom/dingtalk/feishu,管理端配置
  (AppID/AppSecret/AgentID/回调/自动开户/默认部门),登录页自动展示;
  one-time state 防 CSRF,provider_uid 全局唯一防多账号绑定,平台端点
  固定公网 URL 复用 public-only 拨号。
- 个人安全策略:账号安全页(登录设备管理/吊销非当前会话/登录提醒开关/
  扫码绑定解绑),登录成功发布 security.login_detected 事件按偏好落站内信
  (新增 security 类别),会话索引只存令牌摘要并惰性清理。
- 迁移 000038-000041;修复 social update 参数越界/凭据回读/路由挂载缺失;
  全量测试 25 包通过,前端 admin/portal 构建通过,端到端验证完成。
This commit is contained in:
LLMGuardX Dev
2026-08-13 12:53:38 +08:00
parent 4563979a15
commit e31cc54b8e
36 changed files with 2823 additions and 60 deletions
+18 -2
View File
@@ -84,12 +84,27 @@ func (h *ManagementHTTPHandler) registerOIDC() {
func (h *HTTPHandler) registerOIDC() {
h.mux.HandleFunc("GET /api/v1/portal/sso/providers", h.listPublicOIDCProviders)
h.mux.HandleFunc("GET /api/v1/portal/sso/{provider_code}/start", h.startSSO)
h.mux.HandleFunc("GET /api/v1/portal/sso/{provider_code}/callback", h.callbackOIDC)
h.mux.HandleFunc("GET /api/v1/portal/sso/{provider_code}/callback", h.callbackSSO)
h.mux.HandleFunc("POST /api/v1/portal/sso/{provider_code}/callback", h.callbackSAML)
h.mux.HandleFunc("GET /api/v1/portal/sso/{provider_code}/metadata", h.samlMetadata)
h.mux.HandleFunc("POST /api/v1/portal/sso/exchange", h.exchangeOIDC)
}
// callbackSSO 按身份源 kind 分发 GET 回调:OIDC 走标准 code 交换,扫码登录
// 走企微/钉钉/飞书协议。
func (h *HTTPHandler) callbackSSO(w http.ResponseWriter, r *http.Request) {
kind, err := h.service.repository.GetIdentityProviderKind(r.Context(), r.PathValue("provider_code"))
if err != nil {
http.NotFound(w, r)
return
}
if socialKindSupported(kind) {
h.callbackSocial(w, r)
return
}
h.callbackOIDC(w, r)
}
func (h *ManagementHTTPHandler) listOIDCProviders(w http.ResponseWriter, r *http.Request) {
if _, ok := h.requirePermission(w, r); !ok {
return
@@ -349,11 +364,12 @@ func (h *HTTPHandler) callbackOIDC(w http.ResponseWriter, r *http.Request) {
h.writeIdentityError(w, ErrAccountDisabled)
return
}
token, err := h.service.sessions.Create(r.Context(), principalFor(account))
token, err := h.service.sessions.CreateWithMeta(r.Context(), principalFor(account), h.service.ClientIP(r), r.UserAgent())
if err != nil {
h.writeIdentityError(w, err)
return
}
h.service.NotifyLogin(r.Context(), account.ID, SessionMeta{IP: h.service.ClientIP(r), UserAgent: r.UserAgent()})
exchange, err := h.service.sessions.StoreOneTime(r.Context(), "oidc-exchange", oidcExchange{Token: token}, time.Minute)
if err != nil {
h.writeIdentityError(w, err)