This commit is contained in:
laodaming 2023-11-16 16:57:29 +08:00
parent 2aae36dfca
commit f8b8d98723
18 changed files with 490 additions and 5 deletions

View File

@ -0,0 +1,16 @@
package gmodel
import (
"gorm.io/gorm"
)
// ldap_user ldap_用户id递增表
type LdapUser struct {
Id int64 `gorm:"primary_key;default:0;auto_increment;" json:"id"` //
}
type LdapUserModel struct {
db *gorm.DB
name string
}
func NewLdapUserModel(db *gorm.DB) *LdapUserModel { return &LdapUserModel{db: db, name: "ldap_user"} }

View File

@ -6,8 +6,8 @@ import (
// ldap_user_group 用户权限分组表
type LdapUserGroup struct {
GroupId *int64 `gorm:"default:0;" json:"group_id"` //
UserId *string `gorm:"default:'0';" json:"user_id"` //
GroupId *int64 `gorm:"default:0;" json:"group_id"` //
UserId *int64 `gorm:"default:0;" json:"user_id"` //
}
type LdapUserGroupModel struct {
db *gorm.DB

View File

@ -0,0 +1,8 @@
package gmodel
import "context"
// TODO: 使用model的属性做你想做的
func (u *LdapUserModel) Create(ctx context.Context, data *LdapUser) error {
return u.db.WithContext(ctx).Model(&LdapUser{}).Create(&data).Error
}

View File

@ -114,6 +114,7 @@ type AllModelsGen struct {
LdapGroup *LdapGroupModel // ldap_group 权限组表
LdapGroupMenus *LdapGroupMenusModel // ldap_group_menus 权限分组菜单表
LdapMenus *LdapMenusModel // ldap_menus 菜单表
LdapUser *LdapUserModel // ldap_user ldap_用户id递增表
LdapUserGroup *LdapUserGroupModel // ldap_user_group 用户权限分组表
}
@ -230,6 +231,7 @@ func NewAllModels(gdb *gorm.DB) *AllModelsGen {
LdapGroup: NewLdapGroupModel(gdb),
LdapGroupMenus: NewLdapGroupMenusModel(gdb),
LdapMenus: NewLdapMenusModel(gdb),
LdapUser: NewLdapUserModel(gdb),
LdapUserGroup: NewLdapUserGroupModel(gdb),
}
return models

View File

@ -17,6 +17,6 @@ type Config struct {
Password string
BaseDN string
RootDN string
PeopleGroupOu string
PeopleGroupDN string
}
}

View File

@ -0,0 +1,35 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/ldap-admin/internal/logic"
"fusenapi/server/ldap-admin/internal/svc"
"fusenapi/server/ldap-admin/internal/types"
)
func CreateLdapUserHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.CreateLdapUserReq
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewCreateLdapUserLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.CreateLdapUser(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -0,0 +1,35 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/ldap-admin/internal/logic"
"fusenapi/server/ldap-admin/internal/svc"
"fusenapi/server/ldap-admin/internal/types"
)
func DeleteLdapUserHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.DeleteLdapUserReq
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewDeleteLdapUserLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.DeleteLdapUser(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -0,0 +1,35 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/ldap-admin/internal/logic"
"fusenapi/server/ldap-admin/internal/svc"
"fusenapi/server/ldap-admin/internal/types"
)
func GetLdapUserInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.GetLdapUserInfoReq
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewGetLdapUserInfoLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.GetLdapUserInfo(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -62,6 +62,26 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/api/ldap-admin/update_ldap_orgination",
Handler: UpdateLdapOrginationHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/ldap-admin/create_ldap_user",
Handler: CreateLdapUserHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/ldap-admin/update_ldap_user",
Handler: UpdateLdapUserHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/api/ldap-admin/delete_ldap_user",
Handler: DeleteLdapUserHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/api/ldap-admin/get_ldap_user_info",
Handler: GetLdapUserInfoHandler(serverCtx),
},
},
)
}

View File

@ -0,0 +1,35 @@
package handler
import (
"net/http"
"reflect"
"fusenapi/utils/basic"
"fusenapi/server/ldap-admin/internal/logic"
"fusenapi/server/ldap-admin/internal/svc"
"fusenapi/server/ldap-admin/internal/types"
)
func UpdateLdapUserHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.UpdateLdapUserReq
userinfo, err := basic.RequestParse(w, r, svcCtx, &req)
if err != nil {
return
}
// 创建一个业务逻辑层实例
l := logic.NewUpdateLdapUserLogic(r.Context(), svcCtx)
rl := reflect.ValueOf(l)
basic.BeforeLogic(w, r, rl)
resp := l.UpdateLdapUser(&req, userinfo)
if !basic.AfterLogic(w, r, rl, resp) {
basic.NormalAfterLogic(w, r, resp)
}
}
}

View File

@ -0,0 +1,88 @@
package logic
import (
"fmt"
"fusenapi/model/gmodel"
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"fusenapi/utils/chinese_to_pinyin"
"fusenapi/utils/ldap_lib"
"strings"
"context"
"fusenapi/server/ldap-admin/internal/svc"
"fusenapi/server/ldap-admin/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type CreateLdapUserLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewCreateLdapUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CreateLdapUserLogic {
return &CreateLdapUserLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *CreateLdapUserLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *CreateLdapUserLogic) CreateLdapUser(req *types.CreateLdapUserReq, userinfo *auth.UserInfo) (resp *basic.Response) {
req.UserName = strings.Trim(req.UserName, " ")
req.Mobile = strings.Trim(req.Mobile, " ")
req.Email = strings.Trim(req.Email, " ")
req.Password = strings.Trim(req.Password, " ")
if req.UserName == "" {
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "用户名不能为空")
}
if req.Password == "" {
return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "密码不能为空")
}
ldapServer := ldap_lib.NewLdap(l.svcCtx.Ldap, l.svcCtx.Config.Ldap.BaseDN, l.svcCtx.Config.Ldap.RootDN)
//把用户名转pinyin
userNamePinyin := chinese_to_pinyin.ChineseToPinyin(req.UserName)
//新增一条记录获取递增用户id
userData := &gmodel.LdapUser{}
if err := l.svcCtx.AllModels.LdapUser.Create(l.ctx, userData); err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "获取自增用户id失败")
}
userDN := fmt.Sprintf("cn=%s,%s", userNamePinyin, l.svcCtx.Config.Ldap.PeopleGroupDN)
if err := ldapServer.Create(userDN, map[string][]string{
"objectClass": {"person", "organizationalPerson", "inetOrgPerson", "posixAccount", "top", "shadowAccount"}, //固有属性
"shadowLastChange": {"19676"}, //固有属性
"shadowMin": {"0"}, //固有属性
"shadowMax": {"99999"}, //固有属性
"shadowWarning": {"7"}, //固有属性
"loginShell": {"/usr/sbin/nologin"}, //固有属性
"homeDirectory": {"/home/users/" + userNamePinyin},
"uidNumber": {fmt.Sprintf("%d", userData.Id)},
"gidNumber": {fmt.Sprintf("%d", userData.Id)},
"uid": {fmt.Sprintf("%d", userData.Id)},
"cn": {userNamePinyin},
"sn": {req.UserName},
"mail": {req.Email},
"postalCode": {fmt.Sprintf("%d", req.Status)},
"departmentNumber": {"0"},
"postalAddress": {req.Avatar},
"mobile": {req.Mobile},
"userPassword": {req.Password},
}); err != nil {
logx.Error(err)
return resp.SetStatusWithMessage(basic.CodeServiceErr, "添加用户失败,", err.Error())
}
return resp.SetStatusWithMessage(basic.CodeOK, "添加用户成功")
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *CreateLdapUserLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -0,0 +1,43 @@
package logic
import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/ldap-admin/internal/svc"
"fusenapi/server/ldap-admin/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type DeleteLdapUserLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewDeleteLdapUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteLdapUserLogic {
return &DeleteLdapUserLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *DeleteLdapUserLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *DeleteLdapUserLogic) DeleteLdapUser(req *types.DeleteLdapUserReq, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
return resp.SetStatus(basic.CodeOK)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *DeleteLdapUserLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -0,0 +1,43 @@
package logic
import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/ldap-admin/internal/svc"
"fusenapi/server/ldap-admin/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type GetLdapUserInfoLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewGetLdapUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetLdapUserInfoLogic {
return &GetLdapUserInfoLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *GetLdapUserInfoLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *GetLdapUserInfoLogic) GetLdapUserInfo(req *types.GetLdapUserInfoReq, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
return resp.SetStatus(basic.CodeOK)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *GetLdapUserInfoLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -47,7 +47,11 @@ func (l *GetorginationsLogic) Getorginations(req *types.Request, userinfo *auth.
return resp.SetStatusWithMessage(basic.CodeServiceErr, "root用户DN未设置")
}
ldapServer := ldap_lib.NewLdap(l.svcCtx.Ldap, l.svcCtx.Config.Ldap.BaseDN, l.svcCtx.Config.Ldap.RootDN)
filter := "(&(objectClass=*)(!(ou=" + l.svcCtx.Config.Ldap.PeopleGroupOu + "))(!(" + rootCn[0] + ")))" //所有object但是不包括people以及root用户
peopleDNSlice := strings.Split(l.svcCtx.Config.Ldap.PeopleGroupDN, ",")
if len(peopleDNSlice) <= 1 {
return resp.SetStatusWithMessage(basic.CodeServiceErr, "基础用户组的DN未配置")
}
filter := "(&(objectClass=*)(!(" + peopleDNSlice[0] + "))(!(" + rootCn[0] + ")))" //所有object但是不包括people以及root用户
searchResult, err := ldapServer.Search(l.svcCtx.Config.Ldap.BaseDN, filter, nil, nil)
if err != nil {
return resp.SetStatusWithMessage(basic.CodeServiceErr, "查询失败:"+err.Error())

View File

@ -0,0 +1,43 @@
package logic
import (
"fusenapi/utils/auth"
"fusenapi/utils/basic"
"context"
"fusenapi/server/ldap-admin/internal/svc"
"fusenapi/server/ldap-admin/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type UpdateLdapUserLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewUpdateLdapUserLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateLdapUserLogic {
return &UpdateLdapUserLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
// 处理进入前逻辑w,r
// func (l *UpdateLdapUserLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) {
// }
func (l *UpdateLdapUserLogic) UpdateLdapUser(req *types.UpdateLdapUserReq, userinfo *auth.UserInfo) (resp *basic.Response) {
// 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data)
// userinfo 传入值时, 一定不为null
return resp.SetStatus(basic.CodeOK)
}
// 处理逻辑后 w,r 如:重定向, resp 必须重新处理
// func (l *UpdateLdapUserLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) {
// // httpx.OkJsonCtx(r.Context(), w, resp)
// }

View File

@ -88,6 +88,24 @@ type UpdateLdapOrginationReq struct {
BusinessCategory string `json:"business_category"` //组织分类名称
}
type CreateLdapUserReq struct {
UserName string `json:"user_name"` //用户名
Email string `json:"email"` //邮箱
Password string `json:"password"` //密码
Mobile string `json:"mobile"` //手机号
Avatar string `json:"avatar"` //头像地址
Status int64 `json:"status,options=0|1"` //状态 1正常0离职
}
type UpdateLdapUserReq struct {
}
type DeleteLdapUserReq struct {
}
type GetLdapUserInfoReq struct {
}
type Request struct {
}

View File

@ -39,9 +39,21 @@ service ldap-admin {
//删除ldap组织
@handler DeleteLdapOrginationHandler
post /api/ldap-admin/delete_ldap_orgination(DeleteLdapOrginationReq) returns (response);
//修改组织
//修改ldap组织
@handler UpdateLdapOrginationHandler
post /api/ldap-admin/update_ldap_orgination(UpdateLdapOrginationReq) returns (response);
//添加ldap用户到员工基本组中
@handler CreateLdapUserHandler
post /api/ldap-admin/create_ldap_user(CreateLdapUserReq) returns (response);
//修改ldap用户信息
@handler UpdateLdapUserHandler
post /api/ldap-admin/update_ldap_user(UpdateLdapUserReq) returns (response);
//删除ldap用户
@handler DeleteLdapUserHandler
post /api/ldap-admin/delete_ldap_user(DeleteLdapUserReq) returns (response);
//获取ldap用户信息
@handler GetLdapUserInfoHandler
get /api/ldap-admin/get_ldap_user_info(GetLdapUserInfoReq) returns (response);
}
type GetApisReq {
@ -123,4 +135,22 @@ type DeleteLdapOrginationReq {
type UpdateLdapOrginationReq {
OrginationDN string `json:"orgination_dn"` //组织dn
BusinessCategory string `json:"business_category"` //组织分类名称
}
//添加ldap用户到员工基本组中
type CreateLdapUserReq {
UserName string `json:"user_name"` //用户名
Email string `json:"email"` //邮箱
Password string `json:"password"` //密码
Mobile string `json:"mobile"` //手机号
Avatar string `json:"avatar"` //头像地址
Status int64 `json:"status,options=0|1"` //状态 1正常0离职
}
//修改ldap用户信息
type UpdateLdapUserReq {
}
//删除ldap用户
type DeleteLdapUserReq {
}
//获取ldap用户信息
type GetLdapUserInfoReq {
}

View File

@ -0,0 +1,30 @@
package chinese_to_pinyin
import (
"github.com/mozillazg/go-pinyin"
"strings"
"unicode"
)
func ChineseToPinyin(str string) string {
p := pinyin.NewArgs()
p.Style = pinyin.Normal
finalStr := strings.Builder{}
for _, v := range str {
//判断是不是汉字
if isChineseCharacter(v) {
result := pinyin.Pinyin(strings.ToLower(string(v)), p)
r := strings.Builder{}
for _, v := range result {
r.WriteString(v[0])
}
finalStr.WriteString(r.String())
} else {
finalStr.WriteString(string(v))
}
}
return finalStr.String()
}
func isChineseCharacter(c rune) bool {
return unicode.Is(unicode.Scripts["Han"], c)
}