package service import ( "context" "crypto/sha256" "encoding/hex" "errors" "github.com/google/uuid" "github.com/labstack/echo/v4" "golang.org/x/time/rate" "mylomen_server/common/constant" "mylomen_server/common/dto" "mylomen_server/common/email" "mylomen_server/common/logs" "mylomen_server/common/utils" "mylomen_server/common/xjwt" "mylomen_server/infrastructure/convert" "mylomen_server/infrastructure/redis" "mylomen_server/infrastructure/repository" "strings" "time" ) type user struct { } var UserBiz user // 令牌桶大小为 100, 以每秒 10 个 Token 的速率向桶中放置 Token var limiter = rate.NewLimiter(10, 10) // Register 注册 func (l user) Register(ctx context.Context, req dto.RegisterReq) error { acUser := repository.GUser.FindByReq(ctx, req.LoginReq) if acUser != nil && acUser.Deleted == false { return errors.New("user exist") } //fill data userDO := convert.UserReq2DO(req) userDO.Deleted = false userDO.UpdateTime = time.Now() userDO.NickName = req.NickName userDO.Avatar = req.Avatar //密码加密 h := sha256.Sum256([]byte(req.Password)) passHash := hex.EncodeToString(h[:]) userDO.Pwd = &passHash return repository.GUser.Create(ctx, &userDO) } func (l user) Login(ctx context.Context, req dto.LoginReq) (*dto.UserVO, error) { start := time.Now().UnixMilli() //1. 查询用户 acUser := repository.GUser.FindByReq(ctx, req) if acUser == nil || acUser.Deleted == true { return nil, errors.New("user not exist") } //2. email 和 手机号登录 和account 需要验证密码。其他情况不需要验证密码 if req.Account != nil || req.Email != nil || req.Phone != nil { if acUser.Pwd == nil { return nil, errors.New("password not set") } // 验证账号密码 h := sha256.Sum256([]byte(req.Password)) passHash := hex.EncodeToString(h[:]) if acUser.Pwd == nil || passHash != *acUser.Pwd { return nil, errors.New("password is error") } } //3. 组装数据 result := convert.UserDO2VO(*acUser) result.Platform = req.Platform //生成token token := strings.ReplaceAll(uuid.New().String(), "-", "") claims := dto.LoginTokenVo{Sn: result.Sn, Token: token} //设置超时时间 claims.SetExtByPlatform(req.Platform) result.Token = xjwt.GenJwtToken(claims) diff := time.Now().UnixMilli() - start logs.NewLog("").Infof("Login cost: %d", diff) return &result, nil } func (l user) SendResetPwdCode(ctx context.Context, emailP string) error { //1. 验证账号 acUser := repository.GUser.FindByEmail(ctx, emailP) if acUser == nil || acUser.Deleted == true { return errors.New("user not exist") } //2. 生成code & 发送 code := utils.GetPseudoRandomCode(6) //3. save into redis if err := redis.Set(constant.G_RESET_PWD_CODE+emailP, code, time.Duration(30)*time.Minute); err != nil { return errors.New("cache illegal") } //频控 if !limiter.Allow() { return errors.New("rate limit, please try again later") } //4. send code if err := email.SendEmailVerifyCodeByEmail(code, emailP); err != nil { return errors.New("send email code illegal") } return nil } // ResetPwd 重置密码 func (l user) ResetPwd(ctx context.Context, req dto.ResetPwdReq) error { //1. 验证code redisStr, err := redis.Get(constant.G_RESET_PWD_CODE + req.Account) if err != nil && redisStr != req.Code { return errors.New("code is error") } //2. 查询用户 acUser := repository.GUser.FindByAccount(ctx, req.Account) if acUser == nil || acUser.Deleted == true { return errors.New("user not exist") } //3. 重置密码 h := sha256.Sum256([]byte(req.Password)) passHash := hex.EncodeToString(h[:]) acUser.Pwd = &passHash if updateErr := repository.GUser.UpdateById(ctx, acUser); updateErr != nil { logs.NewLog("").Errorf("update user password req:%+v error: %+v", req, updateErr) return errors.New("system error") } return nil } func (l user) GetLoginResult(ctx context.Context, c *echo.Context) (*dto.UserVO, error) { accessToken := utils.GetAccessToken(c) loginVo, err := xjwt.ParseJwtToken(accessToken) if err != nil || loginVo.Sn == "" { return nil, errors.New("token illegal") } //查询数据库 userDO := repository.GUser.FindBySn(ctx, loginVo.Sn) if err != nil || userDO == nil { return nil, errors.New("user not exist") } result := convert.UserDO2VO(*userDO) result.Token = accessToken result.Platform = loginVo.Platform return utils.ToPtr(result), nil }