gin-图形验证码

文档地址:https://mojotv.cn/go/refactor-base64-captcha

1. 在api接口文件中配置生成验证码的代码

在user-web/api下面创建chaptcha.go文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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文件

1
2
3
4
5
6
7
8
9
10
11
12
13
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. 初始化路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

1
{"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配置

1
2
3
4
5
6
if !store.Verify(passWordLoginForm.CaptchaId, passWordLoginForm.Captcha, true) {
    ctx.JSON(http.StatusBadRequest, gin.H{
        "captcha": "验证码错误",
    })
    return
}

  

 

全部内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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验证规则

1
2
3
4
5
6
7
8
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"`
}

  

 

posted @   wanghhhh  阅读(270)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示