feat: 实现LDAP创建OU和用户(LDAP Add)+弹框风格统一

This commit is contained in:
logan committed 2026-05-30 10:24:29 +08:00
1 parent 7b5f95e702
commit c51f619a7d
2 files changed
+167 -49

No files matched your search

+115 -2
View File
@@ -361,12 +361,125 @@ func ListLDAPUsers(c *gin.Context) {
// POST /api/v1/ldap-config/create-ou
func CreateLDAPOU(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "OU created (placeholder)"})
var req struct {
OuName string `json:"ou_name"`
ParentDN string `json:"parent_dn"`
Description string `json:"description"`
}
if err := c.ShouldBindJSON(&req); err != nil || req.OuName == "" {
c.JSON(http.StatusBadRequest, gin.H{"detail": "缺少 ou_name 参数"})
return
}
var cfg model.LDAPConfig
if err := model.DB.Order("id").First(&cfg).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"detail": "LDAP 配置不存在"})
return
}
conn, err := dialLDAP(&cfg)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"detail": "LDAP 连接失败: " + err.Error()})
return
}
defer conn.Close()
adminPw, _ := decryptPassword(cfg.AdminPassword)
if err := conn.Bind(cfg.AdminDN, adminPw); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"detail": "LDAP 管理员绑定失败"})
return
}
ouDN := fmt.Sprintf("ou=%s,%s", ldap.EscapeFilter(req.OuName), req.ParentDN)
addReq := ldap.NewAddRequest(ouDN, nil)
addReq.Attribute("objectClass", []string{"organizationalUnit", "top"})
addReq.Attribute("ou", []string{req.OuName})
if req.Description != "" {
addReq.Attribute("description", []string{req.Description})
}
if err := conn.Add(addReq); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"detail": "创建 OU 失败: " + err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("OU %s 创建成功", req.OuName), "dn": ouDN})
}
// POST /api/v1/ldap-config/create-user
func CreateLDAPUser(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "User created (placeholder)"})
var req struct {
Username string `json:"username"`
DisplayName string `json:"display_name"`
Email string `json:"email"`
Password string `json:"password"`
OuDn string `json:"ou_dn"`
}
if err := c.ShouldBindJSON(&req); err != nil || req.Username == "" || req.Password == "" {
c.JSON(http.StatusBadRequest, gin.H{"detail": "缺少 username 或 password 参数"})
return
}
var cfg model.LDAPConfig
if err := model.DB.Order("id").First(&cfg).Error; err != nil {
c.JSON(http.StatusBadRequest, gin.H{"detail": "LDAP 配置不存在"})
return
}
// Parse user_mapping for attribute names
userMapping := map[string]string{"username": "uid", "email": "mail", "display_name": "cn"}
if cfg.UserMapping != nil && *cfg.UserMapping != "" {
json.Unmarshal([]byte(*cfg.UserMapping), &userMapping)
}
conn, err := dialLDAP(&cfg)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"detail": "LDAP 连接失败: " + err.Error()})
return
}
defer conn.Close()
adminPw, _ := decryptPassword(cfg.AdminPassword)
if err := conn.Bind(cfg.AdminDN, adminPw); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"detail": "LDAP 管理员绑定失败"})
return
}
uidAttr := userMapping["username"]
if uidAttr == "" {
uidAttr = "uid"
}
cnAttr := userMapping["display_name"]
if cnAttr == "" {
cnAttr = "cn"
}
mailAttr := userMapping["email"]
if mailAttr == "" {
mailAttr = "mail"
}
userDN := fmt.Sprintf("%s=%s,%s", uidAttr, ldap.EscapeFilter(req.Username), req.OuDn)
displayName := req.DisplayName
if displayName == "" {
displayName = req.Username
}
addReq := ldap.NewAddRequest(userDN, nil)
addReq.Attribute("objectClass", []string{"inetOrgPerson", "organizationalPerson", "person", "top"})
addReq.Attribute(uidAttr, []string{req.Username})
addReq.Attribute(cnAttr, []string{displayName})
addReq.Attribute("sn", []string{displayName})
addReq.Attribute("userPassword", []string{req.Password})
if req.Email != "" {
addReq.Attribute(mailAttr, []string{req.Email})
}
if err := conn.Add(addReq); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"detail": "创建用户失败: " + err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"message": fmt.Sprintf("用户 %s 创建成功", req.Username), "dn": userDN})
}
// POST /api/v1/ldap-config/batch-import-ldap