Skip to content

Commit 4f468b5

Browse files
committed
feat(password): logout other user when update password
1 parent b50835f commit 4f468b5

File tree

6 files changed

+61
-40
lines changed

6 files changed

+61
-40
lines changed

Diff for: internal/controller/user_controller.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,9 @@ func (uc *UserController) UseRePassWord(ctx *gin.Context) {
183183
return
184184
}
185185

186-
resp, err := uc.userService.UseRePassword(ctx, req)
186+
err := uc.userService.UpdatePasswordWhenForgot(ctx, req)
187187
uc.actionService.ActionRecordDel(ctx, schema.ActionRecordTypeFindPass, ctx.ClientIP())
188-
handler.HandleResponse(ctx, err, resp)
188+
handler.HandleResponse(ctx, err, nil)
189189
}
190190

191191
// UserLogout user logout
@@ -334,15 +334,16 @@ func (uc *UserController) UserVerifyEmailSend(ctx *gin.Context) {
334334
// @Accept json
335335
// @Produce json
336336
// @Security ApiKeyAuth
337-
// @Param data body schema.UserModifyPassWordRequest true "UserModifyPassWordRequest"
337+
// @Param data body schema.UserModifyPasswordReq true "UserModifyPasswordReq"
338338
// @Success 200 {object} handler.RespBody
339339
// @Router /answer/api/v1/user/password [put]
340340
func (uc *UserController) UserModifyPassWord(ctx *gin.Context) {
341-
req := &schema.UserModifyPassWordRequest{}
341+
req := &schema.UserModifyPasswordReq{}
342342
if handler.BindAndCheck(ctx, req) {
343343
return
344344
}
345345
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
346+
req.AccessToken = middleware.ExtractToken(ctx)
346347

347348
oldPassVerification, err := uc.userService.UserModifyPassWordVerification(ctx, req)
348349
if err != nil {

Diff for: internal/repo/auth/auth.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ func (ar *authRepo) AddUserTokenMapping(ctx context.Context, userID, accessToken
148148
}
149149

150150
// RemoveUserTokens Log out all users under this user id
151-
func (ar *authRepo) RemoveUserTokens(ctx context.Context, userID string) {
151+
func (ar *authRepo) RemoveUserTokens(ctx context.Context, userID string, remainToken string) {
152152
key := constant.UserTokenMappingCacheKey + userID
153153
resp, _ := ar.data.Cache.GetString(ctx, key)
154154
mapping := make(map[string]bool, 0)
@@ -158,6 +158,9 @@ func (ar *authRepo) RemoveUserTokens(ctx context.Context, userID string) {
158158
}
159159

160160
for token := range mapping {
161+
if token == remainToken {
162+
continue
163+
}
161164
if err := ar.RemoveUserCacheInfo(ctx, token); err != nil {
162165
log.Error(err)
163166
} else {

Diff for: internal/schema/user_schema.go

+11-7
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ type GetUserResp struct {
7272
RoleID int `json:"role_id"`
7373
// user status
7474
Status string `json:"status"`
75+
// user have password
76+
HavePassword bool `json:"have_password"`
7577
}
7678

7779
func (r *GetUserResp) GetFromUserEntity(userInfo *entity.User) {
@@ -83,11 +85,13 @@ func (r *GetUserResp) GetFromUserEntity(userInfo *entity.User) {
8385
if ok {
8486
r.Status = statusShow
8587
}
88+
r.HavePassword = len(userInfo.Pass) > 0
8689
}
8790

8891
type GetUserToSetShowResp struct {
8992
*GetUserResp
90-
Avatar *AvatarInfo `json:"avatar"`
93+
Avatar *AvatarInfo `json:"avatar"`
94+
HavePassword bool `json:"have_password"`
9195
}
9296

9397
func (r *GetUserToSetShowResp) GetFromUserEntity(userInfo *entity.User) {
@@ -260,14 +264,14 @@ func (u *UserRegisterReq) Check() (errFields []*validator.FormErrorField, err er
260264
return nil, nil
261265
}
262266

263-
// UserModifyPassWordRequest
264-
type UserModifyPassWordRequest struct {
265-
UserID string `json:"-" ` // user_id
266-
OldPass string `json:"old_pass" ` // old password
267-
Pass string `json:"pass" ` // password
267+
type UserModifyPasswordReq struct {
268+
OldPass string `json:"old_pass"`
269+
Pass string `json:"pass"`
270+
UserID string `json:"-"`
271+
AccessToken string `json:"-"`
268272
}
269273

270-
func (u *UserModifyPassWordRequest) Check() (errFields []*validator.FormErrorField, err error) {
274+
func (u *UserModifyPasswordReq) Check() (errFields []*validator.FormErrorField, err error) {
271275
// TODO i18n
272276
err = checker.CheckPassword(8, 32, 0, u.Pass)
273277
if err != nil {

Diff for: internal/service/auth/auth.go

+9-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ type AuthRepo interface {
2020
SetAdminUserCacheInfo(ctx context.Context, accessToken string, userInfo *entity.UserCacheInfo) error
2121
RemoveAdminUserCacheInfo(ctx context.Context, accessToken string) (err error)
2222
AddUserTokenMapping(ctx context.Context, userID, accessToken string) (err error)
23-
RemoveUserTokens(ctx context.Context, userID string)
23+
RemoveUserTokens(ctx context.Context, userID string, remainToken string)
2424
}
2525

2626
// AuthService kit service
@@ -85,9 +85,14 @@ func (as *AuthService) AddUserTokenMapping(ctx context.Context, userID, accessTo
8585
return as.authRepo.AddUserTokenMapping(ctx, userID, accessToken)
8686
}
8787

88-
// RemoveUserTokens Log out all users under this user id
89-
func (as *AuthService) RemoveUserTokens(ctx context.Context, userID string) {
90-
as.authRepo.RemoveUserTokens(ctx, userID)
88+
// RemoveUserAllTokens Log out all users under this user id
89+
func (as *AuthService) RemoveUserAllTokens(ctx context.Context, userID string) {
90+
as.authRepo.RemoveUserTokens(ctx, userID, "")
91+
}
92+
93+
// RemoveTokensExceptCurrentUser remove all tokens except the current user
94+
func (as *AuthService) RemoveTokensExceptCurrentUser(ctx context.Context, userID string, accessToken string) {
95+
as.authRepo.RemoveUserTokens(ctx, userID, accessToken)
9196
}
9297

9398
//Admin

Diff for: internal/service/user_admin/user_backyard.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ func (us *UserAdminService) UpdateUserRole(ctx context.Context, req *schema.Upda
116116
return err
117117
}
118118

119-
us.authService.RemoveUserTokens(ctx, req.UserID)
119+
us.authService.RemoveUserAllTokens(ctx, req.UserID)
120120
return
121121
}
122122

@@ -179,7 +179,7 @@ func (us *UserAdminService) UpdateUserPassword(ctx context.Context, req *schema.
179179
return err
180180
}
181181
// logout this user
182-
us.authService.RemoveUserTokens(ctx, req.UserID)
182+
us.authService.RemoveUserAllTokens(ctx, req.UserID)
183183
return
184184
}
185185

Diff for: internal/service/user_service.go

+30-22
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ func (us *UserService) GetUserInfoByUserID(ctx context.Context, token, userID st
8282
resp.GetFromUserEntity(userInfo)
8383
resp.AccessToken = token
8484
resp.RoleID = roleID
85+
resp.HavePassword = len(userInfo.Pass) > 0
8586
return resp, nil
8687
}
8788

@@ -171,42 +172,43 @@ func (us *UserService) RetrievePassWord(ctx context.Context, req *schema.UserRet
171172
return nil
172173
}
173174

174-
// UseRePassword
175-
func (us *UserService) UseRePassword(ctx context.Context, req *schema.UserRePassWordRequest) (resp *schema.GetUserResp, err error) {
175+
// UpdatePasswordWhenForgot update user password when user forgot password
176+
func (us *UserService) UpdatePasswordWhenForgot(ctx context.Context, req *schema.UserRePassWordRequest) (err error) {
176177
data := &schema.EmailCodeContent{}
177178
err = data.FromJSONString(req.Content)
178179
if err != nil {
179-
return nil, errors.BadRequest(reason.EmailVerifyURLExpired)
180+
return errors.BadRequest(reason.EmailVerifyURLExpired)
180181
}
181182

182183
userInfo, exist, err := us.userRepo.GetByEmail(ctx, data.Email)
183184
if err != nil {
184-
return nil, err
185+
return err
185186
}
186187
if !exist {
187-
return nil, errors.BadRequest(reason.UserNotFound)
188+
return errors.BadRequest(reason.UserNotFound)
188189
}
189190
enpass, err := us.encryptPassword(ctx, req.Pass)
190191
if err != nil {
191-
return nil, err
192+
return err
192193
}
193194
err = us.userRepo.UpdatePass(ctx, userInfo.ID, enpass)
194195
if err != nil {
195-
return nil, err
196+
return err
196197
}
197-
resp = &schema.GetUserResp{}
198-
return resp, nil
198+
// When the user changes the password, all the current user's tokens are invalid.
199+
us.authService.RemoveUserAllTokens(ctx, userInfo.ID)
200+
return nil
199201
}
200202

201-
func (us *UserService) UserModifyPassWordVerification(ctx context.Context, request *schema.UserModifyPassWordRequest) (bool, error) {
202-
userInfo, has, err := us.userRepo.GetByUserID(ctx, request.UserID)
203+
func (us *UserService) UserModifyPassWordVerification(ctx context.Context, req *schema.UserModifyPasswordReq) (bool, error) {
204+
userInfo, has, err := us.userRepo.GetByUserID(ctx, req.UserID)
203205
if err != nil {
204206
return false, err
205207
}
206208
if !has {
207-
return false, fmt.Errorf("user does not exist")
209+
return false, errors.BadRequest(reason.UserNotFound)
208210
}
209-
isPass := us.verifyPassword(ctx, request.OldPass, userInfo.Pass)
211+
isPass := us.verifyPassword(ctx, req.OldPass, userInfo.Pass)
210212
if !isPass {
211213
return false, nil
212214
}
@@ -215,26 +217,29 @@ func (us *UserService) UserModifyPassWordVerification(ctx context.Context, reque
215217
}
216218

217219
// UserModifyPassword user modify password
218-
func (us *UserService) UserModifyPassword(ctx context.Context, request *schema.UserModifyPassWordRequest) error {
219-
enpass, err := us.encryptPassword(ctx, request.Pass)
220+
func (us *UserService) UserModifyPassword(ctx context.Context, req *schema.UserModifyPasswordReq) error {
221+
enpass, err := us.encryptPassword(ctx, req.Pass)
220222
if err != nil {
221223
return err
222224
}
223-
userInfo, has, err := us.userRepo.GetByUserID(ctx, request.UserID)
225+
userInfo, exist, err := us.userRepo.GetByUserID(ctx, req.UserID)
224226
if err != nil {
225227
return err
226228
}
227-
if !has {
228-
return fmt.Errorf("user does not exist")
229+
if !exist {
230+
return errors.BadRequest(reason.UserNotFound)
229231
}
230-
isPass := us.verifyPassword(ctx, request.OldPass, userInfo.Pass)
232+
233+
isPass := us.verifyPassword(ctx, req.OldPass, userInfo.Pass)
231234
if !isPass {
232-
return fmt.Errorf("the old password verification failed")
235+
return errors.BadRequest(reason.OldPasswordVerificationFailed)
233236
}
234237
err = us.userRepo.UpdatePass(ctx, userInfo.ID, enpass)
235238
if err != nil {
236239
return err
237240
}
241+
242+
us.authService.RemoveTokensExceptCurrentUser(ctx, userInfo.ID, req.AccessToken)
238243
return nil
239244
}
240245

@@ -477,8 +482,11 @@ func (us *UserService) UserVerifyEmail(ctx context.Context, req *schema.UserVeri
477482

478483
// verifyPassword
479484
// Compare whether the password is correct
480-
func (us *UserService) verifyPassword(ctx context.Context, LoginPass, UserPass string) bool {
481-
err := bcrypt.CompareHashAndPassword([]byte(UserPass), []byte(LoginPass))
485+
func (us *UserService) verifyPassword(ctx context.Context, loginPass, userPass string) bool {
486+
if len(loginPass) == 0 && len(userPass) == 0 {
487+
return true
488+
}
489+
err := bcrypt.CompareHashAndPassword([]byte(userPass), []byte(loginPass))
482490
return err == nil
483491
}
484492

0 commit comments

Comments
 (0)