// Copyright 2019 github.com. All rights reserved. // Use of this source code is governed by github.com. package v1 import ( "context" "fmt" "git.getensh.com/common/gopkgs/cache" "github.com/tidwall/gjson" "net/http" "property-applete-gateway/errors" param_v1 "property-applete-gateway/param/v1" "property-applete-gateway/pb" "property-applete-gateway/pb/v1" "property-applete-gateway/utils" "time" "git.getensh.com/common/gopkgs/logger" "git.getensh.com/common/gopkgs/tasker/httptasker" "git.getensh.com/common/gopkgs/util" "github.com/dgrijalva/jwt-go" "property-applete-gateway/parser" "git.getensh.com/common/gopkgs/jwtwrapper" "github.com/gin-gonic/gin" "go.uber.org/zap" ) func phonePasswordLogin(req *param_v1.LoginRequest) (param_v1.LoginResponse, error) { resp := param_v1.LoginResponse{} rpcReq := &v1.LoginByPhoneRequest{ Phone:req.User, Password:req.Password, } rpcRsp, err := pb.System.LoginByPhone(context.Background(), rpcReq) if err != nil { s, _ := json.MarshalToString(req) logger.Error("func", zap.String("call", "pb.System.LoginByPhone"), zap.String("params", s), zap.String("error", err.Error())) return resp, err } if len(rpcRsp.List) == 0 { return resp, errors.ErrRecordNotFound } // 只有一条记录 if len(rpcRsp.List) == 1 { now := time.Now() routers := map[string]bool{} for _, v := range rpcRsp.List[0].Permissions { routers[v.Router] = true } subject := map[string]interface{}{ "user_name": req.User, "cid":rpcRsp.List[0].Cid, "garden_id":rpcRsp.List[0].GardenId, "is_super_group":rpcRsp.List[0].IsSuperGroup, "routers":routers, "garden_name":rpcRsp.List[0].GardenName, "g_permission_time":rpcRsp.List[0].GlobalPermissionTime, "u_permission_time":rpcRsp.List[0].UserPermissionTime, "single_sign_time":fmt.Sprintf("%d", now.Unix()), } str, _ := json.MarshalToString(subject) // 生成token token, err := jwtwrapper.GenToken(fmt.Sprintf("%d", rpcRsp.List[0].Uid), parser.Conf.Jwt.Issuer, str, time.Duration(parser.Conf.Jwt.Seconds)*time.Second) if err != nil { logger.Error("func", zap.String("call", "util.GenJwtToken"), zap.String("args", fmt.Sprintf("%d", rpcRsp.List[0].Uid)), zap.String("error", err.Error())) return resp, errors.SystemError } if err = utils.SetSingleSignTime(rpcRsp.List[0].Uid, now.Unix()); err != nil { return resp, err } permissions := []v1.SystemGroupPermissionData{} for _, v := range rpcRsp.List[0].Permissions { // 前端控制的权限 //if v.Front { permissions = append(permissions, *v) //} } resp.Data.Uid = rpcRsp.List[0].Uid resp.Data.Token = token resp.Data.User = req.User resp.Data.Permissions = permissions resp.Data.IsSuper = rpcRsp.List[0].IsSuperGroup return resp, nil } // 多条记录需要选择小区 loginResp, err := makeLoginByPhoneResponse(rpcRsp, req.User) if err != nil { return resp, nil } str, _ := json.MarshalToString(rpcRsp) key := utils.GetKey(utils.SYSTEMPHONELOGINKEY, req.User) _, err = cache.Redis().SetEx(key, 600, str) if err != nil { return resp, errors.RedisError } resp.PhoneData = loginResp.Data return resp, nil } // 登录 // @Summary 登录 // @Description 登录 // @Tags 用户 // @Accept json // @Produce json // @Param body body v1.LoginBody true "登录信息" // @Success 200 {object} v1.LoginResponse // @Failure 500 {object} base.HTTPError // @Router /api/v1/user/login [post] func (c *Controller) Login(ctx *gin.Context) { // 解析参数 req := ¶m_v1.LoginRequest{} parseParamTask := func() error { err := util.ShouldBind(ctx, &req.Header, nil, nil, &req.LoginBody) if err != nil { logger.Error("func", zap.String("call", "util.ShouldBind"), zap.String("error", err.Error())) return errors.ParamsError } if req.Password == "" { return errors.ParamsError } return nil } // 业务处理 handleServiceTask := func() error { // 响应数据 resp := param_v1.LoginResponse{} // 先尝试手机号登录 if utils.VerifyMobileFormat(req.User) { if resp, err := phonePasswordLogin(req); err == nil { ctx.JSON(http.StatusOK, resp) return nil } } rpcReq := &v1.LoginRequest{ Username: req.User, Password: req.Password, } rpcRsp, err := pb.System.Login(ctx, rpcReq) if err != nil { s, _ := json.MarshalToString(req) logger.Error("func", zap.String("call", "pb.System.Login"), zap.String("params", s), zap.String("error", err.Error())) return errors.ErrorTransForm(err) } routers := map[string]bool{} for _, v := range rpcRsp.Permissions { routers[v.Router] = true } now := time.Now() subject := map[string]interface{}{ "user_name": req.User, "cid":rpcRsp.Cid, "garden_id":rpcRsp.GardenId, "is_super_group":rpcRsp.IsSuperGroup, "routers":routers, "garden_name":rpcRsp.GardenName, "g_permission_time":rpcRsp.GlobalPermissionTime, "u_permission_time":rpcRsp.UserPermissionTime, "single_sign_time":fmt.Sprintf("%d", now.Unix()), } str, _ := json.MarshalToString(subject) // 生成token token, err := jwtwrapper.GenToken(fmt.Sprintf("%d", rpcRsp.Uid), parser.Conf.Jwt.Issuer, str, time.Duration(parser.Conf.Jwt.Seconds)*time.Second) if err != nil { logger.Error("func", zap.String("call", "util.GenJwtToken"), zap.String("args", fmt.Sprintf("%d", rpcRsp.Uid)), zap.String("error", err.Error())) return errors.SystemError } if err = utils.SetSingleSignTime(rpcRsp.Uid, now.Unix()); err != nil { return err } permissions := []v1.SystemGroupPermissionData{} for _, v := range rpcRsp.Permissions { // 前端控制的权限 //if v.Front { permissions = append(permissions, *v) //} } resp.Data.Uid = rpcRsp.Uid resp.Data.Token = token resp.Data.User = req.User resp.Data.Permissions = permissions resp.Data.IsSuper = rpcRsp.IsSuperGroup ctx.JSON(http.StatusOK, resp) return nil } // 执行任务 httptasker.Exec(ctx, parseParamTask, handleServiceTask) } // token // @Summary 刷新token // @Description 刷新token // @Tags 用户 // @Accept json // @Produce json // @Param token header string true "token" // @Success 200 {object} v1.TokenResponse // @Failure 500 {object} base.HTTPError // @Router /api/v1/token_refresh [put] func (c *Controller) TokenRefresh(ctx *gin.Context) { // 解析参数 req := ¶m_v1.TokenRequest{} parseParamTask := func() error { err := util.ShouldBind(ctx, &req.Header, nil, nil, nil) if err != nil { logger.Error("func", zap.String("call", "util.ShouldBind"), zap.String("error", err.Error())) return errors.ParamsError } return nil } // 业务处理 handleServiceTask := func() error { tokenObj, err := jwtwrapper.ParseToken(req.Token) if tokenObj == nil { return errors.TokenFailedError } if err != nil { switch err.(*jwt.ValidationError).Errors { case jwt.ValidationErrorExpired: if tokenObj == nil { return errors.TokenFailedError } if time.Now().Unix() - tokenObj.ExpiresAt > 3600{ return errors.TokenFailedError } default: return errors.TokenFailedError } } uid := tokenObj.Id subject := tokenObj.Subject remberPass := gjson.GetBytes([]byte(subject), "rember_password").Bool() // 生成token token, err := jwtwrapper.GenToken(uid, parser.Conf.Jwt.Issuer, subject, time.Duration(parser.Conf.Jwt.Seconds)*time.Second) if err != nil { logger.Error("func", zap.String("call", "util.GenJwtToken"), zap.String("args", fmt.Sprintf("%s", uid)), zap.String("error", err.Error())) return errors.SystemError } refreshTokenTime := time.Duration(24*60*60)*time.Second if remberPass { refreshTokenTime = time.Duration(7*24*60*60)*time.Second } refreshToken, err := jwtwrapper.GenToken(uid, parser.Conf.Jwt.Issuer, subject, refreshTokenTime) if err != nil { logger.Error("func", zap.String("call", "util.GenJwtToken"), zap.String("args", fmt.Sprintf("%s", uid)), zap.String("error", err.Error())) return errors.SystemError } resp := param_v1.TokenResponse{} resp.Data = token resp.RefreshToken = refreshToken ctx.JSON(http.StatusOK, resp) return nil } // 执行任务 httptasker.Exec(ctx, parseParamTask, handleServiceTask) } // // @Summary 获取短信验证码 // @Description 获取短信验证码 // @Tags 用户 // @Accept json // @Produce json // @Param phone query string true " " // @Success 200 {object} v1.GetVcodeResponse // @Failure 500 {object} base.HTTPError // @Router /api/v1/user/vcode [get] func (c *Controller) GetVcode(ctx *gin.Context) { // 解析参数 req := ¶m_v1.GetVcodeRequest{} parseParamTask := func() error { err := util.ShouldBind(ctx, nil, nil, &req.GetVcodeQuery, nil) if err != nil { logger.Error("func", zap.String("call", "util.ShouldBind"), zap.String("error", err.Error())) return errors.ParamsError } return nil } checkPhoneTask := func() error { mreq := &v1.CheckPhoneRequest{Phone:req.Phone} _, err := pb.System.CheckPhone(ctx, mreq) if err != nil { return err } return nil } // 业务处理 handleServiceTask := func() error { // 响应数据 resp := param_v1.GetVcodeResponse{} rpcReq := &v1.GetVcodeRequest{ PhoneNumber:req.Phone, } rpcRsp, err := pb.Thirdparty.GetVcode(ctx, rpcReq) if err != nil { s, _ := json.MarshalToString(req) logger.Error("func", zap.String("call", "Thirdparty.GetVcode"), zap.String("params", s), zap.String("error", err.Error())) return errors.ErrorTransForm(err) } resp.Data = *rpcRsp ctx.JSON(http.StatusOK, resp) return nil } // 执行任务 httptasker.Exec(ctx, parseParamTask, checkPhoneTask, handleServiceTask) } func makeLoginByPhoneToken(rpcRsp *v1.LoginByPhoneReply, phone string) (token string, err error) { uid := int64(0) var subject map[string]interface{} now := time.Now() if len(rpcRsp.List) > 1 { subject = map[string]interface{}{ "phone": phone, "should_choose_garden":true, } uid = 0 } else { routers := map[string]bool{} for _, v := range rpcRsp.List[0].Permissions { routers[v.Router] = true } subject = map[string]interface{}{ "user_name": rpcRsp.List[0].UserName, "cid":rpcRsp.List[0].Cid, "garden_id":rpcRsp.List[0].GardenId, "is_super_group":rpcRsp.List[0].IsSuperGroup, "routers":routers, "phone":phone, "garden_name":rpcRsp.List[0].GardenName, "g_permission_time":rpcRsp.List[0].GlobalPermissionTime, "u_permission_time":rpcRsp.List[0].UserPermissionTime, "single_sign_time":fmt.Sprintf("%d", now.Unix()), } uid = rpcRsp.List[0].Uid } str, _ := json.MarshalToString(subject) token, err = jwtwrapper.GenToken(fmt.Sprintf("%d", uid), parser.Conf.Jwt.Issuer, str, time.Duration(parser.Conf.Jwt.Seconds)*time.Second) if err != nil { logger.Error("func", zap.String("call", "util.GenJwtToken"), zap.String("args", fmt.Sprintf("%d", rpcRsp.List[0].Uid)), zap.String("error", err.Error())) return token, errors.SystemError } if len(rpcRsp.List) == 1 { if err = utils.SetSingleSignTime(rpcRsp.List[0].Uid, now.Unix()); err != nil { return token, err } } return token, nil } func makeLoginByPhoneResponse(rpcRsp *v1.LoginByPhoneReply, phone string) (resp param_v1.LoginByPhoneResponse, err error) { token, err := makeLoginByPhoneToken(rpcRsp, phone) if err != nil { return resp, err } for i, _ := range rpcRsp.List { permissions := []v1.SystemGroupPermissionData{} for _, v := range rpcRsp.List[i].Permissions { permissions = append(permissions, *v) } item := param_v1.LoginByPhoneItem{ Uid:rpcRsp.List[i].Uid, GardenName:rpcRsp.List[i].GardenName, GardenId:rpcRsp.List[i].GardenId, User:rpcRsp.List[i].UserName, Permissions:permissions, IsSuper:rpcRsp.List[i].IsSuperGroup, } resp.Data.List = append(resp.Data.List, item) resp.Data.Token = token } return resp, nil } // // @Summary 手机号登录 // @Description 手机号登录 // @Tags 用户 // @Accept json // @Produce json // @Param body body v1.LoginByPhoneBody true " " // @Success 200 {object} v1.LoginByPhoneResponse // @Failure 500 {object} base.HTTPError // @Router /api/v1/user/login_by_phone [post] func (c *Controller) LoginByPhone(ctx *gin.Context) { // 解析参数 req := ¶m_v1.LoginByPhoneRequest{} loginResp := param_v1.LoginByPhoneResponse{} parseParamTask := func() error { err := util.ShouldBind(ctx, nil, nil, nil, &req.LoginByPhoneBody) if err != nil { logger.Error("func", zap.String("call", "util.ShouldBind"), zap.String("error", err.Error())) return errors.ParamsError } return nil } // 业务处理 handleServiceTask := func() error { // 响应数据 rpcReq := &v1.LoginByPhoneRequest{ Phone:req.Phone, } rpcRsp, err := pb.System.LoginByPhone(ctx, rpcReq) if err != nil { s, _ := json.MarshalToString(req) logger.Error("func", zap.String("call", "Thirdparty.GetVcode"), zap.String("params", s), zap.String("error", err.Error())) return errors.ErrorTransForm(err) } if len(rpcRsp.List) == 0 { return errors.ErrRecordNotFound } loginResp, err = makeLoginByPhoneResponse(rpcRsp, req.Phone) if err != nil { return err } str, _ := json.MarshalToString(rpcRsp) key := utils.GetKey(utils.SYSTEMPHONELOGINKEY, req.Phone) _, err = cache.Redis().SetEx(key, 600, str) if err != nil { return errors.RedisError } return nil } checkVcodeTask := func() error { rpcReq := &v1.CheckVcodeRequest{ PhoneNumber:req.Phone, Vcode:req.Vcode, } _, err := pb.Thirdparty.CheckVcode(ctx, rpcReq) if err != nil { s, _ := json.MarshalToString(req) logger.Error("func", zap.String("call", "pb.Thirdparty.CheckVcode"), zap.String("params", s), zap.String("error", err.Error())) return errors.ErrorTransForm(err) } ctx.JSON(http.StatusOK, loginResp) return nil } // 执行任务 httptasker.Exec(ctx, parseParamTask, handleServiceTask, checkVcodeTask) } // // @Summary 手机号登录选择账户 // @Description 手机号登录选择账户 // @Tags 用户 // @Accept json // @Produce json // @Param token header string true "token" // @Param id query int true "账户id" // @Success 200 {object} v1.ChooseUserResponse // @Failure 500 {object} base.HTTPError // @Router /api/v1/user/choose_user [get] func (c *Controller) ChooseUser(ctx *gin.Context) { // 解析参数 req := ¶m_v1.ChooseUserRequest{} parseParamTask := func() error { err := util.ShouldBind(ctx, &req.Header, nil, &req.ChooseUserQuery, nil) if err != nil { logger.Error("func", zap.String("call", "util.ShouldBind"), zap.String("error", err.Error())) return errors.ParamsError } return nil } // 业务处理 handleServiceTask := func() error { tokenInfo, err := utils.GetSubjectValue(ctx) if err != nil { return err } resp := param_v1.ChooseUserResponse{} // 获取缓存的用户信息 key := utils.GetKey(utils.SYSTEMPHONELOGINKEY, tokenInfo.Phone) str, err := cache.Redis().Get(key) if str == "" { return errors.SystemError } loginByPhoneResp := v1.LoginByPhoneReply{} json.Unmarshal([]byte(str), &loginByPhoneResp) var userInfo *v1.LoginReply // 搜索目标小区 for _, v := range loginByPhoneResp.List { if v.Uid == req.Id { userInfo = v break } } if userInfo == nil { return errors.SystemError } now := time.Now() // 构造响应数据 routers := map[string]bool{} for _, v := range userInfo.Permissions { routers[v.Router] = true } subject := map[string]interface{}{ "user_name": userInfo.UserName, "cid":userInfo.Cid, "garden_id":userInfo.GardenId, "is_super_group":userInfo.IsSuperGroup, "routers":routers, "garden_name":userInfo.GardenName, "g_permission_time":userInfo.GlobalPermissionTime, "u_permission_time":userInfo.UserPermissionTime, "single_sign_time":fmt.Sprintf("%d", now.Unix()), } str, _ = json.MarshalToString(subject) // 生成token token, err := jwtwrapper.GenToken(fmt.Sprintf("%d", userInfo.Uid), parser.Conf.Jwt.Issuer, str, time.Duration(parser.Conf.Jwt.Seconds)*time.Second) if err != nil { logger.Error("func", zap.String("call", "util.GenJwtToken"), zap.String("args", fmt.Sprintf("%d", userInfo.Uid)), zap.String("error", err.Error())) return errors.SystemError } permissions := []v1.SystemGroupPermissionData{} for _, v := range userInfo.Permissions { permissions = append(permissions, *v) } if err = utils.SetSingleSignTime(userInfo.Uid, now.Unix()); err != nil { return err } resp.Data.Uid = userInfo.Uid resp.Data.Token = token resp.Data.User = userInfo.UserName resp.Data.IsSuper = userInfo.IsSuperGroup resp.Data.Permissions = permissions cache.Redis().Del(key) ctx.JSON(http.StatusOK, resp) return nil } // 执行任务 httptasker.Exec(ctx, parseParamTask, handleServiceTask) } // // @Summary 忘记密码重置密码 // @Description 忘记密码重置密码 // @Tags 用户 // @Accept json // @Produce json // @Param body body v1.ResetPasswordBody true "信息" // @Success 200 {object} v1.ResetPasswordResponse // @Failure 500 {object} base.HTTPError // @Router /api/v1/user/reset_password [put] func (c *Controller) ResetPassword(ctx *gin.Context) { // 解析参数 req := ¶m_v1.ResetPasswordRequest{} parseParamTask := func() error { err := util.ShouldBind(ctx, nil, nil, nil, &req.ResetPasswordBody) if err != nil { logger.Error("func", zap.String("call", "util.ShouldBind"), zap.String("error", err.Error())) return errors.ParamsError } return nil } // 业务处理 handleServiceTask := func() error { // 响应数据 resp := param_v1.ResetPasswordResponse{} rpcReq := &v1.ResetPasswordRequest{ Uid:req.Uid, Phone:req.Phone, Vcode:req.Vcode, Password: req.Password, } rpcRsp, err := pb.System.ResetPassword(ctx, rpcReq) if err != nil { s, _ := json.MarshalToString(req) logger.Error("func", zap.String("call", "pb.System.ResetPassword"), zap.String("params", s), zap.String("error", err.Error())) return errors.ErrorTransForm(err) } if rpcRsp.List == nil { rpcRsp.List = make([]*v1.ResetPasswordData, 0) } resp.Data = *rpcRsp ctx.JSON(http.StatusOK, resp) if len(rpcRsp.List) == 1 { logReq := OperationLogRequest{ Module:ModuleSelf, Action:ActionSelfResetPassword, Origin:nil, Target:nil, UserName:"", Uid:rpcRsp.List[0].Uid, Cid:0, GardenId:0, } go OperationLogAdd(&logReq) } return nil } // 执行任务 httptasker.Exec(ctx, parseParamTask, handleServiceTask) } // // @Summary 修改密码 // @Description 修改密码 // @Tags 用户 // @Accept json // @Produce json // @Param token header string true " " // @Param body body v1.ChangePasswordBody true "信息" // @Success 200 {object} v1.ChangePasswordResponse // @Failure 500 {object} base.HTTPError // @Router /api/v1/user/change_password [put] func (c *Controller) ChangePassword(ctx *gin.Context) { // 解析参数 req := ¶m_v1.ChangePasswordRequest{} parseParamTask := func() error { err := util.ShouldBind(ctx, nil, nil, nil, &req.ChangePasswordBody) if err != nil { logger.Error("func", zap.String("call", "util.ShouldBind"), zap.String("error", err.Error())) return errors.ParamsError } return nil } // 业务处理 handleServiceTask := func() error { tokenInfo, err := utils.GetSubjectValue(ctx) if err != nil { return err } // 响应数据 resp := param_v1.ChangePasswordResponse{} rpcReq := &v1.ChangePasswordRequest{ Uid:tokenInfo.Uid, OldPassword:req.OldPassword, NewPassword:req.NewPassword, } _, err = pb.System.ChangePassword(ctx, rpcReq) if err != nil { s, _ := json.MarshalToString(req) logger.Error("func", zap.String("call", "pb.System.ChangePassword"), zap.String("params", s), zap.String("error", err.Error())) return errors.ErrorTransForm(err) } ctx.JSON(http.StatusOK, resp) logReq := OperationLogRequest{ Module:ModuleSelf, Action:ActionSelfChangePassword, Origin:nil, Target:nil, UserName:tokenInfo.UserName, Uid:tokenInfo.Uid, Cid:tokenInfo.Cid, GardenId:tokenInfo.GardenId, } go OperationLogAdd(&logReq) return nil } // 执行任务 httptasker.Exec(ctx, parseParamTask, handleServiceTask) }