refactor: 移除 SAML/LDAP/MFA 登录方式,仅保留本地账号密码和 OIDC
后端移除: - SAML: auth/saml.go, handler/saml_handler.go, account_saml_settings_handler.go, model/account_saml_settings.go, model/saml_idp_config.go, repo/*.go - LDAP: auth/ldap.go, handler/ldap_handler.go, model/account_ldap_settings.go, repo/account_ldap_settings_repo.go - MFA: auth/mfa.go, handler/mfa_handler.go - auth_service: 移除 mfaService 依赖、MFARequired 字段、LoginWithMFA 方法 - auth_handler: 移除 LoginMFA handler、MFA 分支逻辑 - bootstrap: 移除 SAML/LDAP/MFA service 初始化和 handler 注册 - sso_middleware: 精简为仅支持 OIDC provider - router: 移除 SAML/LDAP/MFA 路由注册 - config: 移除 SAMLConfig/LDAPConfig struct 和 defaults 前端移除: - v3/login: 移除 MFA 验证流程和 SAML 登录入口 - v3/api/auth: 移除 MFA 响应处理 - v3/routes: 移除 SSO login 路由 - dashboard: 移除 MFA 设置页面、SAML 安全设置页面 - i18n: 移除 mfa.json - featureFlags: 移除 SAML feature flag .env.example / .env: 移除 SAML/LDAP 配置段
This commit is contained in:
@@ -52,12 +52,6 @@ type LoginRequest struct {
|
||||
Password string `json:"password" binding:"required,min=6"`
|
||||
}
|
||||
|
||||
// LoginMFAResquest is the JSON body for MFA login verification.
|
||||
type LoginMFAResquest struct {
|
||||
UserID uint `json:"user_id" binding:"required"`
|
||||
TOTPCode string `json:"totp_code" binding:"required"`
|
||||
}
|
||||
|
||||
// RefreshRequest is the JSON body for refresh endpoint.
|
||||
type RefreshRequest struct {
|
||||
RefreshToken string `json:"refresh_token" binding:"required"`
|
||||
@@ -87,7 +81,6 @@ type ConfirmEmailRequest struct {
|
||||
|
||||
// Login authenticates a user with email/password and returns JWT tokens.
|
||||
// POST /api/v1/auth/login
|
||||
// If MFA is enabled, returns mfa_required=true with user_id for TOTP verification.
|
||||
func (h *AuthHandler) Login(c *gin.Context) {
|
||||
var req LoginRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
@@ -104,15 +97,6 @@ func (h *AuthHandler) Login(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if output.MFARequired {
|
||||
response.OK(c, gin.H{
|
||||
"mfa_required": true,
|
||||
"user_id": output.User.ID,
|
||||
"message": "MFA verification required, please provide TOTP code",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
response.OK(c, gin.H{
|
||||
"user": output.User,
|
||||
"access_token": output.TokenPair.AccessToken,
|
||||
@@ -141,13 +125,6 @@ func (h *AuthHandler) ChatwootSignIn(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if output.MFARequired {
|
||||
c.JSON(http.StatusPartialContent, gin.H{
|
||||
"mfa_required": true,
|
||||
"mfa_token": strconv.FormatUint(uint64(output.User.ID), 10),
|
||||
})
|
||||
return
|
||||
}
|
||||
if err := h.trackChatwootSession(c, output); err != nil {
|
||||
response.AbortWithStatusError(c, http.StatusInternalServerError, response.ErrInternal, "failed to create session")
|
||||
return
|
||||
@@ -213,31 +190,6 @@ func (h *AuthHandler) ChatwootSignOut(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"success": true})
|
||||
}
|
||||
|
||||
// LoginMFA completes login after MFA TOTP code verification.
|
||||
// POST /api/v1/auth/login/mfa
|
||||
func (h *AuthHandler) LoginMFA(c *gin.Context) {
|
||||
var req LoginMFAResquest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.AbortWithStatusError(c, http.StatusBadRequest, response.ErrValidation, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
output, err := h.authService.LoginWithMFA(c.Request.Context(), req.UserID, req.TOTPCode)
|
||||
if err != nil {
|
||||
response.AbortWithStatusError(c, http.StatusUnauthorized, response.ErrUnauthorized, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
response.OK(c, gin.H{
|
||||
"user": output.User,
|
||||
"access_token": output.TokenPair.AccessToken,
|
||||
"refresh_token": output.TokenPair.RefreshToken,
|
||||
"expires_at": output.TokenPair.ExpiresAt,
|
||||
"account_id": output.AccountID,
|
||||
"role": output.Role,
|
||||
})
|
||||
}
|
||||
|
||||
// Refresh rotates a refresh token and returns new JWT pair.
|
||||
// POST /api/v1/auth/refresh
|
||||
// Implements refresh token rotation per P2E §1.4 security requirement.
|
||||
@@ -423,7 +375,6 @@ func RegisterAuthRoutes(rg *gin.RouterGroup, handler *AuthHandler) {
|
||||
{
|
||||
// Core auth endpoints
|
||||
authGroup.POST("/login", handler.Login)
|
||||
authGroup.POST("/login/mfa", handler.LoginMFA)
|
||||
authGroup.POST("/refresh", handler.Refresh)
|
||||
authGroup.DELETE("/logout", handler.Logout)
|
||||
|
||||
@@ -488,7 +439,7 @@ func extractChatwootAccessToken(c *gin.Context) string {
|
||||
}
|
||||
|
||||
// generateOAuthState creates a cryptographically random state token for CSRF protection.
|
||||
// Used by SAML and other auth flows. Production note: state should also be stored
|
||||
// Used by OIDC and other auth flows. Production note: state should also be stored
|
||||
// server-side (Redis) and validated on callback.
|
||||
func generateOAuthState() string {
|
||||
return "gochat_oauth_" + randomHex(16)
|
||||
|
||||
Reference in New Issue
Block a user