Skip to content

Commit 1ba9c68

Browse files
eryajferyajf
authored andcommitted
feat: 添加用户密码重置功能并优化用户创建通知邮件
1 parent be24bfa commit 1ba9c68

File tree

10 files changed

+151
-3
lines changed

10 files changed

+151
-3
lines changed

.cnb/workflows/build-docker-images.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ main:
1515
ALIHUB_IMAGE_REPONAME: eryajf
1616
stages:
1717
- name: 📦 构建制品
18-
image: docker.cnb.cool/znb/images/debian:all
18+
image: docker.cnb.cool/znb/images/debian:new
1919
script: |
2020
docker cp $(docker create --rm docker.cnb.cool/opsre/go-ldap-admin-ui):/app/dist public/static/dist
2121
make gox-linux

.github/workflows/build-docker-image.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ jobs:
2929
buildImage:
3030
runs-on: ubuntu-latest
3131
steps:
32-
- uses: actions/checkout@v4
32+
- uses: actions/checkout@v5
3333
- name: Inject slug/short variables
34-
uses: rlespinasse/github-slug-action@v4
34+
uses: rlespinasse/github-slug-action@v5
3535
- name: Get current date
3636
id: date
3737
run: echo "today=$(date +'%Y%m%d-%H%M')" >> $GITHUB_OUTPUT

controller/user_controller.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,23 @@ func (m UserController) ChangePwd(c *gin.Context) {
9393
})
9494
}
9595

96+
// ResetPassword 重置用户密码
97+
// @Summary 重置用户密码
98+
// @Description 重置用户密码为随机密码并发送邮件通知
99+
// @Tags 用户管理
100+
// @Accept application/json
101+
// @Produce application/json
102+
// @Param data body request.UserResetPasswordReq true "重置用户密码的结构体"
103+
// @Success 200 {object} response.ResponseBody
104+
// @Router /user/resetPassword [post]
105+
// @Security ApiKeyAuth
106+
func (m UserController) ResetPassword(c *gin.Context) {
107+
req := new(request.UserResetPasswordReq)
108+
Run(c, req, func() (any, any) {
109+
return logic.User.ResetPassword(c, req)
110+
})
111+
}
112+
96113
// ChangeUserStatus 更改用户状态
97114
// @Summary 更改用户状态
98115
// @Description 更改用户状态

logic/a_logic.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ func CommonAddUser(user *model.User, groups []*model.Group) error {
123123
if err != nil {
124124
return tools.NewMySqlError(fmt.Errorf("%s", "向MySQL创建用户失败:"+err.Error()))
125125
}
126+
127+
// 发送用户创建成功通知邮件
128+
if err := tools.SendUserCreationNotification(user.Username, user.Nickname, user.Mail, tools.NewParPasswd(user.Password)); err != nil {
129+
common.Log.Warnf("发送用户创建通知邮件失败,用户: %s, 邮箱: %s, 错误: %v", user.Username, user.Mail, err)
130+
}
126131
// 再将用户添加到ldap
127132
err = ildap.User.Add(user)
128133
if err != nil {

logic/user_logic.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/eryajf/go-ldap-admin/model"
99
"github.com/eryajf/go-ldap-admin/model/request"
1010
"github.com/eryajf/go-ldap-admin/model/response"
11+
"github.com/eryajf/go-ldap-admin/public/common"
1112
"github.com/eryajf/go-ldap-admin/public/tools"
1213
"github.com/eryajf/go-ldap-admin/service/ildap"
1314
"github.com/eryajf/go-ldap-admin/service/isql"
@@ -371,6 +372,49 @@ func (l UserLogic) ChangePwd(c *gin.Context, req any) (data any, rspError any) {
371372
return nil, nil
372373
}
373374

375+
// ResetPassword 重置用户密码
376+
func (l UserLogic) ResetPassword(c *gin.Context, req any) (data any, rspError any) {
377+
r, ok := req.(*request.UserResetPasswordReq)
378+
if !ok {
379+
return nil, ReqAssertErr
380+
}
381+
_ = c
382+
383+
// 检查用户是否存在
384+
if !isql.User.Exist(tools.H{"username": r.Username}) {
385+
return nil, tools.NewValidatorError(fmt.Errorf("用户不存在"))
386+
}
387+
388+
// 获取用户信息
389+
user := new(model.User)
390+
err := isql.User.Find(tools.H{"username": r.Username}, user)
391+
if err != nil {
392+
return nil, tools.NewMySqlError(fmt.Errorf("获取用户信息失败: %s", err.Error()))
393+
}
394+
395+
// 生成随机密码
396+
newPassword := tools.GenerateRandomPassword()
397+
398+
// 在LDAP中更新密码
399+
err = ildap.User.ChangePwd(user.UserDN, "", newPassword)
400+
if err != nil {
401+
return nil, tools.NewLdapError(fmt.Errorf("在LDAP更新密码失败: %s", err.Error()))
402+
}
403+
404+
// 在MySQL中更新密码
405+
err = isql.User.ChangePwd(user.Username, tools.NewGenPasswd(newPassword))
406+
if err != nil {
407+
return nil, tools.NewMySqlError(fmt.Errorf("在MySQL更新密码失败: %s", err.Error()))
408+
}
409+
410+
// 发送密码重置通知邮件
411+
if err := tools.SendPasswordResetNotification(user.Username, user.Nickname, user.Mail, newPassword); err != nil {
412+
common.Log.Warnf("发送密码重置通知邮件失败,用户: %s, 邮箱: %s, 错误: %v", user.Username, user.Mail, err)
413+
}
414+
415+
return map[string]string{"newPassword": newPassword}, nil
416+
}
417+
374418
// ChangeUserStatus 修改用户状态
375419
func (l UserLogic) ChangeUserStatus(c *gin.Context, req any) (data any, rspError any) {
376420
r, ok := req.(*request.UserChangeUserStatusReq)

model/request/user_req.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ type UserChangePwdReq struct {
9494
NewPassword string `json:"newPassword" validate:"required"`
9595
}
9696

97+
// UserResetPasswordReq 重置密码结构体
98+
type UserResetPasswordReq struct {
99+
Username string `json:"username" validate:"required"`
100+
}
101+
97102
// UserChangeUserStatusReq 修改用户状态结构体
98103
type UserChangeUserStatusReq struct {
99104
ID uint `json:"id" validate:"required"`

public/common/init_mysql_data.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,13 @@ func InitData() {
320320
Remark: "更新用户登录密码",
321321
Creator: "系统",
322322
},
323+
{
324+
Method: "POST",
325+
Path: "/user/resetPassword",
326+
Category: "user",
327+
Remark: "重置用户密码",
328+
Creator: "系统",
329+
},
323330
{
324331
Method: "POST",
325332
Path: "/user/add",

public/tools/bcrypt_passwd.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package tools
22

33
import (
4+
"crypto/rand"
5+
"math/big"
6+
47
"github.com/eryajf/go-ldap-admin/config"
58
)
69

@@ -32,3 +35,21 @@ func NewParPasswd(passwd string) string {
3235
pass, _ := RSADecrypt([]byte(passwd), config.Conf.System.RSAPrivateBytes)
3336
return string(pass)
3437
}
38+
39+
const (
40+
passwordLength = 8
41+
letters = "abcdefghijklmnopqrstu@vwxyzABCDEFGHIJKL#MNOP*QRSTUVWXYZ0123456789"
42+
lettersLength = len(letters)
43+
)
44+
45+
// 生成随机密码
46+
func GenerateRandomPassword() string {
47+
password := make([]byte, passwordLength)
48+
49+
for i := range password {
50+
index, _ := rand.Int(rand.Reader, big.NewInt(int64(lettersLength)))
51+
password[i] = letters[index.Int64()]
52+
}
53+
54+
return string(password)
55+
}

public/tools/email.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,51 @@ func SendCode(sendto []string) error {
6464
</div>`, vcode)
6565
return email(sendto, subject, body)
6666
}
67+
68+
// SendUserCreationNotification 发送用户创建成功通知邮件
69+
func SendUserCreationNotification(username, nickname, mail, password string) error {
70+
subject := "LDAP账户创建成功通知"
71+
// 邮件正文
72+
body := fmt.Sprintf(`<div>
73+
<div>
74+
尊敬的%s,您好!
75+
</div>
76+
<div style="padding: 8px 40px 8px 50px;">
77+
<p>您的LDAP账户已创建成功,以下是您的账户信息:</p>
78+
<ul>
79+
<li>用户名:%s</li>
80+
<li>昵称:%s</li>
81+
<li>初始密码:%s</li>
82+
</ul>
83+
<p style="color: #ff6600;">请妥善保管您的账户信息,建议首次登录后及时修改密码。</p>
84+
</div>
85+
<div>
86+
<p>此邮箱为系统邮箱,请勿回复。</p>
87+
</div>
88+
</div>`, nickname, username, nickname, password)
89+
return email([]string{mail}, subject, body)
90+
}
91+
92+
// SendPasswordResetNotification 发送密码重置成功通知邮件
93+
func SendPasswordResetNotification(username, nickname, mail, newPassword string) error {
94+
subject := "LDAP密码重置成功通知"
95+
// 邮件正文
96+
body := fmt.Sprintf(`<div>
97+
<div>
98+
尊敬的%s,您好!
99+
</div>
100+
<div style="padding: 8px 40px 8px 50px;">
101+
<p>您的LDAP账户密码已成功重置,以下是您的新密码信息:</p>
102+
<ul>
103+
<li>用户名:%s</li>
104+
<li>新密码:%s</li>
105+
</ul>
106+
<p style="color: #ff6600;">为了您的账户安全,请尽快登录并修改为您自己的密码。</p>
107+
<p style="color: #ff0000;">请妥善保管您的账户信息,切勿泄露给他人。</p>
108+
</div>
109+
<div>
110+
<p>此邮箱为系统邮箱,请勿回复。</p>
111+
</div>
112+
</div>`, nickname, username, newPassword)
113+
return email([]string{mail}, subject, body)
114+
}

routes/user_routes.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ func InitUserRoutes(r *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) gi
2222
user.POST("/update", controller.User.Update) // 更新用户
2323
user.POST("/delete", controller.User.Delete) // 删除用户
2424
user.POST("/changePwd", controller.User.ChangePwd) // 修改用户密码
25+
user.POST("/resetPassword", controller.User.ResetPassword) // 重置用户密码
2526
user.POST("/changeUserStatus", controller.User.ChangeUserStatus) // 修改用户状态
2627

2728
user.POST("/syncDingTalkUsers", controller.User.SyncDingTalkUsers) // 同步钉钉用户到平台

0 commit comments

Comments
 (0)