gin-图形验证码
文档地址:https://mojotv.cn/go/refactor-base64-captcha
1. 在api接口文件中配置生成验证码的代码
在user-web/api下面创建chaptcha.go文件
package api
//导入
import (
"github.com/gin-gonic/gin"
"github.com/mojocn/base64Captcha"
"go.uber.org/zap"
"net/http"
)
//文档:https://mojotv.cn/go/refactor-base64-captcha
// 做验证码保存
var store = base64Captcha.DefaultMemStore
func GetCaptcha(ctx *gin.Context) {
driver := base64Captcha.NewDriverDigit(240, 80, 5, 0.7, 80)
cp := base64Captcha.NewCaptcha(driver, store)
id, b64s, err := cp.Generate()
if err != nil {
zap.S().Errorf("生成验证码错误,: ", err.Error())
ctx.JSON(http.StatusInternalServerError, gin.H{
"msg": "生成验证码错误",
})
return
}
ctx.JSON(http.StatusOK, gin.H{
"captchaId":id,
"picPath": b64s,
})
}
2. 添加路由
在user-web/route下面创建base.go文件
package router
import (
"github.com/gin-gonic/gin"
"mxshop-api/user-web/api"
)
func InitBaseRoute(Route *gin.RouterGroup) {
BaseRoute := Route.Group("base")
{
BaseRoute.GET("captcha", api.GetCaptcha)
}
}
3. 初始化路由
package initialize
import (
"github.com/gin-gonic/gin"
"mxshop-api/user-web/middlewares"
"mxshop-api/user-web/router"
)
func Routers() *gin.Engine {
Router := gin.Default()
//配置跨域
Router.Use(middlewares.Cors())
ApiGroup := Router.Group("v1")
router.InitUserRoute(ApiGroup)
router.InitBaseRoute(ApiGroup)
return Router
}
4. 请求接口
http://127.0.0.1:8021/v1/base/captcha
{"captchaId":"Y2C3XDKk92GQExz44SqM","picPath":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAADwCAMAAACg0xNxAAAA81BMVEUAAAB+MGtwIl10JmFyJF9qHFdnGVS/cayIOnWCNG+NP3qsXpldD0qAMm2cTolSBD99L2qxY56gUo2MPnlpG1aiVI+dT4qzZaB6LGfFd7KoWpVaDEejVZB3KWSURoHNf7rKfLekVpG6bKePQXyxY55uIFtvIVxzJWCHOXRPATx8LmmfUYxkFlF7LWiSRH+KPHeIOnVnGVRhE06KPHfEdrF6LGeSRH/OgLtqHFdRAz5xI16HOXRVB0LCdK93KWSyZJ+bTYhjFVBlF1JcDkm1Z6KrXZhwIl2CNG9XCURyJF+8bqmRQ358Lml7LWiwYp1iFE+dT4rWbgCSAAAAAXRSTlMAQObYZgAAA6VJREFUeJzs21lL60AUB/CJIFwXWn0Q8cEd+lBQXFCjVUEpoqDf/+tcbNLMdpI5M+cft87/wdt2Or+epGluMpmo35mT4DuuuxpfPe8kJF5fd4ivr74Y8GIrROZBDbHew3AIFsEV9pOigGJ1cGDNVs8w6NQoFFHrdDqdOYVeA+IKtYEo1OrerNNEs+o361sQLc2qiAMr0qqoesJc/jPKNLad+YuNHADPzgixfqDUQDOqebFesyu8CnUBRVEMBoO5Ym3yn39XVtpE1zMfDMwVqFtn//A8B1TuplPYbe2Mt8DKWHLdZqyPUF3Or9f6Xq338UBjieZ/vAIdMQC6sn7qNfMqtHv5BclAs3/bK8mg27G1xL14u7PEvb14cV6h9f9OeoXu7ssBL+M9VZj7X9e7TBEdubPCHarjVZfY/Zk7O4R4ddUqhhOs8DTdJnN6ChfB3u/MLdq7hYtgz0747CvSC54fRotgb3GyhvbW4CLjPfsxIOOgc39/Jh75LbuExzksrrwjT9zdpcSwV4dXYU4OJ5JjNtITHQWSItjLyfm2HKK9Q0dcFouOtywWlT0WvXwj96zR8psbgGg9k3t95jm6hzv653jPsaI3PumKkV6owkXLP7T3Dy6CvRwnq2hvFS6CPXHG1eU1nDceq+lUJA7VgSVeXMgqHA4PDizxQqIpv8I/mffm0TbGe5+L29sgsXmE8XKI3KG9u0Y8BomNdwwSm1AecrKEgUKYEkyWZWk9ly97KevOSj/fEF7so0x4etrcv2zJ0/df9JIb+69E1BMlnoLNYCJdumEkMn10NKJE/hCmnhxUXbJXakR8Ttwga6Fda+bRJKnC9kwmE4BiiWDva9J5YpRw2bLz1C3pwiq6QlHIORNNzjva6B8vOatDe+ftIv3jxVeYw0yPR+y8vATFSO8lKEYG7fHyhvbe4CLYy1nIbKG9rWjxKSBGe08BMTpy72/sTzbkH2PdtrSxIRadG6vQFeb87EAn5t2Cp/rN5sSiK8xBBj3GWZYleIJ5yZoCHzeixPDgY1S/YPz0iyK4/eIzS54nuaFDqaUlX+T0a9+IPI+VfKeHTtoa7PD871jVEwpSRdIbM0X2sBHXaxnYSk8vA1ubaG8TLoK9v5AfcIocEsHeT0toBk/snBJrjtE94UXPejG9e0qM9KwQXs5i5gPtfcDFtoZvvCuPeTjF96rDKeCFxMqzLnU+Srx6grrlPQpEcgo9osJFyDraW4eL+uH/AAAA///Hyj6PdBcIyQAAAABJRU5ErkJggg=="}
5. 验证
在密码验证之前先对验证码进行验证
在api/user.go中PassWordLogin配置
if !store.Verify(passWordLoginForm.CaptchaId, passWordLoginForm.Captcha, true) {
ctx.JSON(http.StatusBadRequest, gin.H{
"captcha": "验证码错误",
})
return
}
全部内容如下
unc PassWordLogin(ctx *gin.Context) {
//密码登录的接口
//1.表单验证, 在forms中定义
//ctx.JSON(http.StatusOK, "密码登录")
passWordLoginForm := forms.PassWordLoginForm{}
//固定格式
if err := ctx.ShouldBind(&passWordLoginForm); err != nil {
HandleValidatorError(ctx, err)
return
}
if !store.Verify(passWordLoginForm.CaptchaId, passWordLoginForm.Captcha, true) {
ctx.JSON(http.StatusBadRequest, gin.H{
"captcha": "验证码错误",
})
return
}
//拨号连接用户RPC服务
userConn, err := grpc.Dial(fmt.Sprintf("%s:%d", global.ServerConfig.UserSrvInfo.Host, global.ServerConfig.UserSrvInfo.Port), grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
zap.S().Errorw("[GetUserList]连接失败【用户服务失败】", "msg", err.Error())
}
//生成grpc的client并调用接口
userSrvClient := proto.NewUserClient(userConn)
// 登录的逻辑, 查询是否存在,密码是否相等
if rsp, err := userSrvClient.GetUserByMobile(context.Background(), &proto.MobileRequests{
Mobile: passWordLoginForm.Mobile,
}); err != nil {
if e, ok := status.FromError(err); ok {
switch e.Code() {
case codes.NotFound:
ctx.JSON(http.StatusBadRequest, map[string]string{
"mobile": "用户不存在",
})
default:
ctx.JSON(http.StatusBadRequest, map[string]string{
"mobile": "登录失败",
})
}
return
}
} else {
// 只是查询了用户而已,并没有检查密码
if passRsp, pasErr := userSrvClient.CheckPassWord(context.Background(), &proto.PasswordCheckInfo{
Password: passWordLoginForm.PassWord,
EncryptedPassword: rsp.PassWord,
}); pasErr != nil {
ctx.JSON(http.StatusInternalServerError, map[string]string{
"password": "登录失败",
})
} else {
if passRsp.Success {
//生成token
j := middlewares.NewJWT()
claims := models.CustomClaims{
ID: uint(rsp.Id),
NickName: rsp.NickName,
AuthorityId: uint(rsp.Role),
StandardClaims: jwt.StandardClaims{
NotBefore: time.Now().Unix(), //签名的生效时间
ExpiresAt: time.Now().Unix() + 60*60*24*30, //30day过期
Issuer: "wanghui",
},
}
token, err := j.CreateToken(claims)
if err != nil {
ctx.JSON(http.StatusInternalServerError, map[string]string{
"msg": "生成token失败",
})
return
}
ctx.JSON(http.StatusOK, gin.H{
"id": rsp.Id,
"nick_name": rsp.NickName,
"token": token,
"expired_at": time.Now().Unix() + 60*60*24*30*1000,
})
} else {
ctx.JSON(http.StatusBadRequest, map[string]string{
"msg": "登录失败",
})
}
}
}
}
修改PassWordLoginForm验证规则
package forms
type PassWordLoginForm struct {
Mobile string `form:"mobile" json:"mobile" binding:"required,mobile"` //手机号码规则验证,自定义validator
PassWord string `form:"password" json:"password" binding:"required,min=3,max=20"`
Captcha string `form:"captcha" json:"captcha" binding:"required,min=5,max=5"`
CaptchaId string `form:"captcha_id" json:"captcha_id" binding:"required,min=5"`
}

浙公网安备 33010602011771号