diff --git a/httptest/user.http b/httptest/user.http new file mode 100644 index 0000000..2d0a21e --- /dev/null +++ b/httptest/user.http @@ -0,0 +1,29 @@ +### login +POST http://127.0.0.1:8080/api/user/auth/login +Content-Type: application/json + +{ + "username": "admin", + "password": "123456" +} + +### verify login state +GET http://127.0.0.1:8080/api/user/auth/login + +### change self password +POST http://127.0.0.1:8080/api/user/update +Content-Type: application/json + +{ + "old_password": "123456", + "new_password": "654321@AaBbCc" +} + +### relogin with new password +POST http://127.0.0.1:8080/api/user/auth/login +Content-Type: application/json + +{ +"username": "admin", +"password": "654321@AaBbCc" +} diff --git a/internal/api/api.go b/internal/api/api.go index 04ad686..ecbf7f8 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -37,6 +37,8 @@ func initApp(ctx context.Context) *nf.App { api.Get("/auth/login", auth.NewAuth(), handler.AuthVerify) api.Post("/auth/logout", auth.NewAuth(), oplog.NewOpLog(ctx), handler.AuthLogout) + api.Post("/update", auth.NewAuth(), handler.UserUpdate) + mng := api.Group("/manage") mng.Use(auth.NewAuth(), privilege.Verify( privilege.RelationAnd, diff --git a/internal/controller/user.go b/internal/controller/user.go index 0b2ee50..26eb855 100644 --- a/internal/controller/user.go +++ b/internal/controller/user.go @@ -23,6 +23,7 @@ type userController interface { GetUserByToken(ctx context.Context, token string) (*model.User, error) CacheUser(ctx context.Context, user *model.User) error CacheToken(ctx context.Context, token string, user *model.User) error + RmToken(ctx context.Context, token string) error RmUserCache(ctx context.Context, id uint64) error DeleteUser(ctx context.Context, id uint64) error } @@ -118,6 +119,17 @@ func (u uc) CacheToken(ctx context.Context, token string, user *model.User) erro key := fmt.Sprintf("%s:user:token:%s", opt.CachePrefix, strs[2]) return cache.Client.SetEx(tool.Timeout(3), key, user.Id, opt.TokenTimeout) } + +func (u uc) RmToken(ctx context.Context, token string) error { + strs := strings.Split(token, ".") + if len(strs) != 3 { + return fmt.Errorf("controller.CacheToken: jwt token invalid") + } + + key := fmt.Sprintf("%s:user:token:%s", opt.CachePrefix, strs[2]) + return cache.Client.Del(tool.Timeout(3), key) +} + func (u uc) RmUserCache(ctx context.Context, id uint64) error { key := fmt.Sprintf("%s:user:id:%d", opt.CachePrefix, id) return cache.Client.Del(tool.Timeout(3), key) diff --git a/internal/handler/user.go b/internal/handler/user.go index aa43ba6..c016118 100644 --- a/internal/handler/user.go +++ b/internal/handler/user.go @@ -76,11 +76,18 @@ func AuthLogin(c *nf.Ctx) error { bs []byte ) + // 获取之前的 token if bs, err = cache.Client.Get(tool.Timeout(3), last); err == nil { key := fmt.Sprintf("%s:user:token:%s", opt.CachePrefix, string(bs)) _ = cache.Client.Del(tool.Timeout(3), key) } + // 删掉之前的 token + if len(bs) > 0 { + _ = controller.UserController.RmToken(c.Context(), string(bs)) + } + + // 将当前的 token 存入 last_token if err = cache.Client.Set(tool.Timeout(3), last, token); err != nil { return resp.Resp500(c, err.Error()) } @@ -129,6 +136,70 @@ func AuthLogout(c *nf.Ctx) error { return resp.Resp200(c, nil) } +func UserUpdate(c *nf.Ctx) error { + type Req struct { + OldPassword string `json:"old_password"` + NewPassword string `json:"new_password"` + } + + type Model struct { + Password string `gorm:"column:password"` + } + + var ( + ok bool + err error + req = new(Req) + user *model.User + m = new(Model) + ) + + if user, ok = c.Locals("user").(*model.User); !ok { + return resp.Resp401(c, nil) + } + + if err = c.BodyParser(req); err != nil { + return resp.Resp400(c, err) + } + + if req.OldPassword == "" || req.NewPassword == "" { + return resp.Resp400(c, req) + } + + if err = tool.CheckPassword(req.NewPassword); err != nil { + return resp.Resp400(c, req, err.Error()) + } + + if err = db.New(tool.Timeout(3)). + Select("password"). + Model(&model.User{}). + Where("username = ?", user.Username). + Where("deleted_at = 0"). + Take(m). + Error; err != nil { + return resp.Resp500(c, err.Error()) + } + + if !tool.ComparePassword(req.OldPassword, m.Password) { + return resp.Resp400(c, nil, "原密码错误") + } + + if err = db.New(tool.Timeout(5)). + Model(&model.User{}). + Where("id = ?", user.Id). + Update("password", tool.NewPassword(req.NewPassword)). + Error; err != nil { + return resp.Resp500(c, err.Error()) + } + + _ = controller.UserController.RmUserCache(c.Context(), user.Id) + // todo delete token + + c.SetHeader("Set-Cookie", fmt.Sprintf("%s=;Path=/", opt.CookieName)) + + return resp.Resp200(c, nil, "修改成功, 请重新登录") +} + func ManageUserList(c *nf.Ctx) error { type Req struct { Page int `query:"page"`