欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 高考 > 【Go】十二、业务逻辑:验证器与登录的基本逻辑

【Go】十二、业务逻辑:验证器与登录的基本逻辑

2024/10/24 20:17:44 来源:https://blog.csdn.net/weixin_41365204/article/details/139598319  浏览:    关键词:【Go】十二、业务逻辑:验证器与登录的基本逻辑

验证器与登录的基本逻辑

分页逻辑传入处理

利用 context.getDefaultQuery(key, defaultValue

)快速取出url参数中的query参数:

	// 生成 grpc 的 client 并调用接口userSrvClient := proto.NewUserClient(userConn)// 通过上下文 gin.Context 获取请求参数// 若能找到对应的请求参数,则返回传入的请求参数,若不存在,则返回默认值pn := ctx.DefaultQuery("pn", "0")pnInt, _ := strconv.Atoi(pn)pSize := ctx.DefaultQuery("psize", "10")pSizeInt, _ := strconv.Atoi(pSize)rsp, err := userSrvClient.GetUserList(context.Background(), &proto.PageInfo{Pn:    uint32(pnInt),PSize: uint32(pSizeInt),})

之后这样访问就可以指定参数,若不指定,则默认是第一页展示10个

http://127.0.0.1:8021/u/v1/user/list?pn=0&psize=1

用户登录逻辑错误处理及验证器配置

目录:

user-web

api

user.go

forms

user.go

global

global.go

validate

validators.go (验证器的位置)

基础错误处理和简单验证器

一、 在 user.go 中建立方法,方法参数为 ctx *gin.Context

api/user.go:

// 用户登录模块
func PassWordLogin(c *gin.Context) {}

二、在 form 目录中添加对应的结构

form/user.go

package forms// 这里要注意 binding 内部的参数不可以加空格
type PassWordLoginForm struct {Mobile   string `form:"mobile" json:"mobile" binding:"required"`PassWord string `form:"password" json:"password" binding:"required,min=3,max=10"`
}

三、配置错误处理

  • 在全局变量中配置 Trans

global/global.go

package globalimport (ut "github.com/go-playground/universal-translator"
)// 全局变量
var (// 用于进行错误处理Trans ut.Translator
)
  • 在初始化中添加验证器的初始化内容

initialize/validator.go

package initializeimport ("fmt""reflect""strings""github.com/gin-gonic/gin/binding""github.com/go-playground/locales/en""github.com/go-playground/locales/zh"ut "github.com/go-playground/universal-translator""github.com/go-playground/validator/v10"en_translations "github.com/go-playground/validator/v10/translations/en"zh_translations "github.com/go-playground/validator/v10/translations/zh""mxshop-api/user-web/global"
)// 下面这一切主要也是为了 global.Trans 的使用
func InitTrans(locale string) (err error) {// 定制化 gin 中的 validator 引擎if v, ok := binding.Validator.Engine().(*validator.Validate); ok {// 注册 json tag 的自定义方案v.RegisterTagNameFunc(func(fld reflect.StructField) string {name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]if name == "-" {return ""}return name})zhT := zh.New()enT := en.New()// 第一个参数是备用语言环境,后面是支持的语言环境uni := ut.New(enT, zhT, enT)global.Trans, ok = uni.GetTranslator(locale)if !ok {return fmt.Errorf("uni.GetTranslator(%s)", locale)}switch locale {case "en":en_translations.RegisterDefaultTranslations(v, global.Trans)case "zh":zh_translations.RegisterDefaultTranslations(v, global.Trans)default:en_translations.RegisterDefaultTranslations(v, global.Trans)}return}return
}
  • 在 main.go 中配置初始化验证器
package mainimport ("fmt""go.uber.org/zap""mxshop-api/user-web/global""mxshop-api/user-web/initialize"
)func main() {// 调用配置文件伛initialize.InitConfig()// 调用自己的 initlize 创建 RouterRouter := initialize.Routers()//port := 8021// 配置日志级别,自定义方法initialize.InitLogger()// 添加::::初始化翻译。验证器工作,配置翻译为中文initialize.InitTrans("zh")// 打印日志// 这里的 S() 和 L() 方法的主要用途是:在底层创建安全的日志情况,否则我们自己写的话需要自己考虑加锁的问题zap.L().Debug(fmt.Sprintf("启动服务器,端口:%d", global.ServerConfig.Port))if err := Router.Run(fmt.Sprintf(":%d", global.ServerConfig.Port)); err != nil {zap.L().Panic("启动失败:", zap.Error(err))}}
  • 核心代码逻辑编写:

api/user.go

// 在最后返回错误时调用,用来将返回中的对象名去掉
func removeTopStruct(fields map[string]string) map[string]string {rsp := map[string]string{}for field, err := range fields {rsp[field[strings.Index(field, ".")+1:]] = err // 将map中的 key 中的 . 前面的信息去掉}return rsp
}// 用户登录模块
func PassWordLogin(c *gin.Context) {passwordLoginForm := forms.PassWordLoginForm{}if err := c.ShouldBind(&passwordLoginForm); err != nil {errs, ok := err.(validator.ValidationErrors)if !ok {c.JSON(http.StatusOK, gin.H{"msg": err.Error(),})}c.JSON(http.StatusBadRequest, gin.H{"msg": removeTopStruct(errs.Translate(global.Trans)),})return}
}
  • 配置http访问路径

router/user.go

package routerimport ("github.com/gin-gonic/gin""mxshop-api/user-web/api"
)func InitUserRouter(Router *gin.RouterGroup) {// 这样就需要 /user/list 才可以进行访问了UserRouter := Router.Group("user"){UserRouter.GET("list", api.GetUserList)UserRouter.POST("pwd_login", api.PassWordLogin)	// 新配置的路径}
}
  • 由于主逻辑中,错误处理信息有点长,所以这里选择使用抽取的方式缩减代码

api/user.go

func HandleValidatorError(c *gin.Context, err error) {errs, ok := err.(validator.ValidationErrors)if !ok {c.JSON(http.StatusOK, gin.H{"msg": err.Error(),})}c.JSON(http.StatusBadRequest, gin.H{"msg": removeTopStruct(errs.Translate(global.Trans)),})return
}// 用户登录模块
func PassWordLogin(c *gin.Context) {passwordLoginForm := forms.PassWordLoginForm{}if err := c.ShouldBind(&passwordLoginForm); err != nil {HandleValidatorError(c, err)}
}

复杂验证器-手机号验证器自定义配置

在 validate 包中定义 validators.go 文件,用来存放自定义的验证器:

validators.go

package validatorimport ("regexp""github.com/go-playground/validator/v10"
)func ValidateMobile(fl validator.FieldLevel) bool {// 利用正则判断是否验证通过mobile := fl.Field().String()// 使用 正则 判断字符串是否合法ok, _ := regexp.MatchString(`^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$`, mobile)if !ok {// ok 为false。代表正则匹配失败,后续整体返回 false 代表验证失败return false}return true
}

在 main 中将创建的验证器注册到 gin 中:

import ("github.com/go-playground/validator/v10"myValidator "mxshop-api/user-web/validator"
)func main() {...Router := initialize.Routers()// 初始化翻译。验证器工作,配置翻译为中文if err := initialize.InitTrans("zh"); err != nil {panic(err)}// 获取验证器的对象,这里会将获取的 Engine 转换为 validator.Validate 对象,若转换成功,ok 会返回 trueif v, ok := binding.Validator.Engine().(*validator.Validate); ok {_ = v.RegisterValidation("mobile", myValidator.ValidateMobile)}...
}

将验证逻辑注入到对应的变量中:

在 required 后面添加 mobile 参数

forms/user.go

package forms// 这里要注意 binding 内部的参数不可以加空格
type PassWordLoginForm struct {Mobile   string `form:"mobile" json:"mobile" binding:"required,mobile"`PassWord string `form:"password" json:"password" binding:"required,min=3,max=10"`
}

修改 main 中的注册内容,令其可以翻译为中文:

	// 获取验证器的对象,这里会将获取的 Engine 转换为 validator.Validate 对象,若转换成功,ok 会返回 trueif v, ok := binding.Validator.Engine().(*validator.Validate); ok {_ = v.RegisterValidation("mobile", myValidator.ValidateMobile)// 错误翻译器注册:v.RegisterTranslation("mobile", global.Trans, func(ut ut.Translator) error {return ut.Add("mobile", "{0} must have a value", true)}, func(ut ut.Translator, fe validator.FieldError) string {t, _ := ut.T("mobile", fe.Field())return t})}

登录功能的核心逻辑编写

无需其他接口配合,仅需这一个逻辑,逻辑为,该接口接收前端参数,进行拨号连接并生成NewUserClient对象,利用该对象在数据库进行比对。

api/user.go:

// 用户登录模块
func PassWordLogin(c *gin.Context) {// 绑定请求参数passwordLoginForm := forms.PassWordLoginForm{}if err := c.ShouldBind(&passwordLoginForm); err != nil {HandleValidatorError(c, err)}// 将请求参数转发给 rpc 服务器//ip := "127.0.0.1"//port := 50051// 拨号连接用户 GRPC 服务userConn, err := grpc.Dial(fmt.Sprintf("%s:%d", global.ServerConfig.UserSrvInfo.Host, global.ServerConfig.UserSrvInfo.Port), grpc.WithInsecure())if err != nil {zap.L().Error("[PassWordLogin] 连接 【用户服务失败】",zap.String("msg", err.Error()))}// 生成 grpc 的 client 并调用接口userSrvClient := proto.NewUserClient(userConn)if rsp, err := userSrvClient.GetUserByMobile(context.Background(), &proto.MobileRequest{Mobile: passwordLoginForm.Mobile,}); err != nil {if e, ok := status.FromError(err); ok {switch e.Code() {case codes.NotFound:c.JSON(http.StatusBadRequest, map[string]string{"mobile": "用户不存在",})default:c.JSON(http.StatusInternalServerError, map[string]string{"mobile": "登录失败",})}return}} else {// TODO 这里只能验证找到了用户,后面继续验证密码是否正确的功能// 这里是调用的 Srv 中的服务进行登录逻辑的判断,传入的 第二个参数是需要的参数,这个参数的对应取值在之前已经取到// 这里仅仅演示简单的登录密码验证机制,完全的登录逻辑在之后展示if passRsp, passErr := userSrvClient.CheckPassWord(context.Background(), &proto.PassWordCheckInfo{Password:          passwordLoginForm.PassWord,EncryptedPassword: rsp.Password,}); passErr != nil {c.JSON(http.StatusInternalServerError, map[string]string{"msg": "登录失败",})} else {// 这里代表未发生其他错误,继续验证密码if passRsp.Success {c.JSON(http.StatusOK, map[string]string{"msg": "登录成功",})} else {// 这里代表登录密码验证错误c.JSON(http.StatusBadRequest, map[string]string{"msg": "密码错误",})}}}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com