【Go】十四、图形验证码、短信验证码、注册接口与redis的简单使用

图形验证码

如何嵌入图形验证码工作:

这里选择使用captcha 开源库进行验证码设计:

选用下面的地址进行验证码开发工作

https://zh.mojotv.cn/go/refactor-base64-captcha

基础功能构建

在 api 目录下创建 captcha.go 用来编写验证码操作

package api

import (
	"github.com/gin-gonic/gin"
	"github.com/mojocn/base64Captcha"
	"go.uber.org/zap"
	"net/http"
)

// 使用内存方式存储验证码信息
var store = base64Captcha.DefaultMemStore

func GetCaptcha(ctx *gin.Context) {
	// 配置验证码参数,数字、高:80、宽:240,长度:5、倾斜程度:0.7、背景圆圈数量:80
	driver := base64Captcha.NewDriverDigit(80, 240, 5, 0.7, 80)
	
	// 结合参数与生成方式,创建验证码生成器
	cp := base64Captcha.NewCaptcha(driver, store)
	
	id, b64s, _, err := cp.Generate()
	if err != nil {
		zap.S().Errorf("生成验证码错误:%s", err.Error())
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg": "验证码生成错误",
		})
	}
	// 若没有发生错误:将图片id 和 图片的 base64 编码作为参数传递
	ctx.JSON(http.StatusOK, gin.H{
		"captchaId": id,
		"picPath": b64s,
	})
}

功能嵌入路由

将验证码放入路由:

在 router 目录下创建文件:base.go:

package api

import (
	"github.com/gin-gonic/gin"
	"github.com/mojocn/base64Captcha"
	"go.uber.org/zap"
	"net/http"
)

// 使用内存方式存储验证码信息
var store = base64Captcha.DefaultMemStore

func GetCaptcha(ctx *gin.Context) {
	// 配置验证码参数,数字、高:240、宽:80,长度:5、倾斜程度:0.7、背景圆圈数量:80
	driver := base64Captcha.NewDriverDigit(80, 240, 5, 0.7, 80)

	// 结合参数与生成方式,创建验证码生成器
	cp := base64Captcha.NewCaptcha(driver, store)

	id, b64s, _, err := cp.Generate()
	if err != nil {
		zap.S().Errorf("生成验证码错误:%s", err.Error())
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg": "验证码生成错误",
		})
	}
	// 若没有发生错误:将图片id 和 图片的 base64 编码作为参数传递
	ctx.JSON(http.StatusOK, gin.H{
		"captchaId": id,
		"picPath":   b64s,
	})
}

将base 的router 配置到初始化的 Initialize 目录中的 router 初始化中:

func Routers() *gin.Engine {
	Router := gin.Default()

	// 配置跨域的拦截器
	Router.Use(middlewares.Cors())

	ApiGroup := Router.Group("/u/v1")
	router2.InitUserRouter(ApiGroup)
	router2.InitBaseRouter(ApiGroup)
	return Router
}

我们可以在前端直接做一个展示:

<img src="data:image/png;base64,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" alt="">

将验证码验证逻辑添加到登录逻辑中:

修改 form/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"`
	Captcha    string `form:"captcha" json:"captcha" binding:"required,min=5,max=5"`
	Captcha_id string `form:"captcha_id" json:"captcha_id" binding:"required"`
}

再对 api/user.go 中的登录方法进行改造:

	// 绑定请求参数
	passwordLoginForm := forms.PassWordLoginForm{}
	if err := c.ShouldBind(&passwordLoginForm); err != nil {
		HandleValidatorError(c, err)
	}
	
	// 下面是新增部分,再请求参数绑定后 进行验证码验证逻辑
	// 直接使用 store 进行验证码验证,由于store 是在同一个 package 下的,所以该变量也可以直接使用
	// 若验证不正确则报错
	if !store.Verify(passwordLoginForm.CaptchaId, passwordLoginForm.Captcha, true) {
		c.JSON(http.StatusBadRequest, gin.H{
			"captcha": "验证码错误",
		})
		return
	}

之后POST访问登录:

BODY:
{
    "mobile": "13001350015",
    "password": "admin123",
    "captchaId": "y2uaAcBujzdUXz0DgX6b",
    "captcha": "56570"
}

短信验证码

阿里云短信接口

稍后在 api 目录下进行开发,构建 api/sms.go 用来处理短信验证码的核心逻辑:

package api

import (
	"fmt"
	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/dysmsapi"
	"github.com/gin-gonic/gin"
)

func SendSms(ctx *gin.Context) {
	client, err := dysmsapi.NewClientWithAccessKey("cn-beijing", 你的acessKey, 你的acessSecret)
	if err != nil {
		panic(err)
	}
	request := requests.NewCommonRequest()
	request.Method = "POST"
	request.Scheme = "https"
	request.Domain = "dysmsapi.aliyuncs.com"
	request.Version = "2017-05-25"	// 必须写这个日期
	request.ApiName = "SendSms"
	// 直接写,无需在阿里云上配置
	request.QueryParams["RegionId"] = "cn-beijing"
	request.QueryParams["PhoneNumbers"] = 发送的手机号
	// 这里要写 签名的名字,注意是名字
	request.QueryParams["SignName"] = 你的签名名称
	// 这里要写模版的 id,注意是 id
	request.QueryParams["TemplateCode"] = 你的模版id
	// 参照你的模版发送请求,注意中间的验证码是可以自定义生成的
	request.QueryParams["TemplateParam"] = "{\"code\":" + "77777" + "}"
	response, err := client.ProcessCommonRequest(request)
	fmt.Println(client.DoAction(request, response))
	if err != nil {
		fmt.Println(err.Error())
	}
	fmt.Printf("response is %#v\n", response)
}

添加随机生成验证码的逻辑:
api/sms.go:

package api

import (
	"fmt"
	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/dysmsapi"
	"github.com/gin-gonic/gin"
	"math/rand"
	"strings"
	"time"
)

// 随机验证码的生成
func GenerateSmsCode(width int) string {
	numeric := [10]byte{0,1,2,3,4,5,6,7,8,9}
	r := len(numeric)
	// 随机数种子
	rand.Seed(time.Now().Unix())
	
	var sb strings.Builder
	for i := 0; i < width; i++ {
		fmt.Fprintf(&sb, "%d", numeric[rand.Intn(r)])
	}
	return sb.String()
}

func SendSms(ctx *gin.Context) {
	client, err := dysmsapi.NewClientWithAccessKey("cn-beijing", "LTAI5tHRZ7GqMXx271nxuSgd", "tJErGmml9ArkhJmMoo0QK1BaJnlCWM")
	if err != nil {
		panic(err)
	}
	request := requests.NewCommonRequest()
	request.Method = "POST"
	request.Scheme = "https"
	request.Domain = "dysmsapi.aliyuncs.com"
	request.Version = "2017-05-25"
	request.ApiName = "SendSms"
	// 直接写,无需在阿里云上配置
	request.QueryParams["RegionId"] = "cn-beijing"
	request.QueryParams["PhoneNumbers"] = "13001350015"
	// 这里要写 签名的名字,注意是名字
	request.QueryParams["SignName"] = "清河个人博客网站"
	// 这里要写模版的 id,注意是 id
	request.QueryParams["TemplateCode"] = "SMS_461975751"
	// 参照你的模版发送请求,注意中间的验证码是可以自定义生成的
	request.QueryParams["TemplateParam"] = "{\"code\":" + GenerateSmsCode(6) + "}"
	response, err := client.ProcessCommonRequest(request)
	fmt.Println(client.DoAction(request, response))
	if err != nil {
		fmt.Println(err.Error())
	}
	fmt.Printf("response is %#v\n", response)
	// TODO 将验证码保存到 redis 以手机号为 key, 以验证码为 value

}

验证码redis存储

虚拟机拉取 redis:

docker run -d --name redis -p 6379:6379 \
-v /mydata/redis:/usr/local/etc/redis \
redis

redis 默认数据库有 16 个 (0 - 15)

默认连接会连接到第一个 0 的 redis 数据库

将短信中的信息修改为从配置文件中读取:

在 config/config,go 中进行添加需要的配置信息:

package config

type UserSrvConfig struct {
	Host string `mapstructure:"host"`
	Port int32  `mapstructure:"port"`
}

type ServerConfig struct {
	Name        string        `mapstructure:"name"`
	Port        int32         `mapstructure:"port"`
	UserSrvInfo UserSrvConfig `mapstructure:"user_srv"`
	JWTInfo     JWTConfig     `mapstructure:"jwt"`
	AliSmsInfo  AliSmsConfig  `mapstructure:"sms"`
	RedisInfo   RedisConfig   `mapstructure:"redis"`
}

type JWTConfig struct {
	SigningKey string `mapstructure:"key"`
}

// redis 配置
type RedisConfig struct {
	Host   string `mapstructure:"host"`
	Port   uint   `mapstructure:"port"`
	Expire int    `mapstructure:"expire"`
}

// 阿里云信息配置
type AliSmsConfig struct {
	ApiKey    string `mapstructure:"key"`
	ApiSecret string `mapstructure:"secret"`
}

配置文件的修改不再显示,这里显示修改之后的核心代码:

package api

import (
	"context"
	"fmt"
	"math/rand"
	"mxshop-api/user-web/forms"
	"net/http"
	"strings"
	"time"

	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/dysmsapi"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"

	"mxshop-api/user-web/global"
)

// 随机验证码的生成
func GenerateSmsCode(width int) string {
	numeric := [10]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	r := len(numeric)
	// 随机数种子
	rand.Seed(time.Now().Unix())

	var sb strings.Builder
	for i := 0; i < width; i++ {
		fmt.Fprintf(&sb, "%d", numeric[rand.Intn(r)])
	}
	return sb.String()
}

func SendSms(ctx *gin.Context) {
	// 表单验证 要求必须传入手机号和 验证码类型
	sendSmsForm := forms.SendSmsForm{}
	if err := ctx.ShouldBind(&sendSmsForm); err != nil {
		HandleValidatorError(ctx, err)
		return
	}

	client, err := dysmsapi.NewClientWithAccessKey("cn-beijing", global.ServerConfig.AliSmsInfo.ApiKey, global.ServerConfig.AliSmsInfo.ApiSecret)
	smsCode := GenerateSmsCode(6)
	if err != nil {
		panic(err)
	}
	request := requests.NewCommonRequest()
	request.Method = "POST"
	request.Scheme = "https"
	request.Domain = "dysmsapi.aliyuncs.com"
	request.Version = "2017-05-25"
	request.ApiName = "SendSms"
	// 直接写,无需在阿里云上配置
	request.QueryParams["RegionId"] = "cn-beijing"
	request.QueryParams["PhoneNumbers"] = sendSmsForm.Mobile
	// 这里要写 签名的名字,注意是名字
	request.QueryParams["SignName"] = "清河个人博客网站"
	// 这里要写模版的 id,注意是 id
	request.QueryParams["TemplateCode"] = "SMS_461975751"
	// 参照你的模版发送请求,注意中间的验证码是可以自定义生成的
	request.QueryParams["TemplateParam"] = "{\"code\":" + smsCode + "}"
	response, err := client.ProcessCommonRequest(request)
	fmt.Println(client.DoAction(request, response))
	if err != nil {
		fmt.Println(err.Error())
	}
	fmt.Printf("response is %#v\n", response)

	// 将验证码保存到 redis 以手机号为 key, 以验证码为 value
	rdb := redis.NewClient(&redis.Options{
		Addr: fmt.Sprintf("%s:%d", global.ServerConfig.RedisInfo.Host, global.ServerConfig.RedisInfo.Port),
	})
	rdb.Set(context.Background(), sendSmsForm.Mobile, smsCode, time.Duration(global.ServerConfig.RedisInfo.Expire)*time.Second)

	ctx.JSON(http.StatusOK, gin.H{
		"msg": "验证码发送成功",
	})
}

将验证码存储进 redis

拉取 redis 的 go 语言库:go-redis:

package api

import (
	"context"
	"fmt"
	"math/rand"
	"strings"
	"time"

	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
	"github.com/aliyun/alibaba-cloud-sdk-go/services/dysmsapi"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"

	"mxshop-api/user-web/global"
)

// 随机验证码的生成
func GenerateSmsCode(width int) string {
	numeric := [10]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	r := len(numeric)
	// 随机数种子
	rand.Seed(time.Now().Unix())

	var sb strings.Builder
	for i := 0; i < width; i++ {
		fmt.Fprintf(&sb, "%d", numeric[rand.Intn(r)])
	}
	return sb.String()
}

func SendSms(ctx *gin.Context) {
	client, err := dysmsapi.NewClientWithAccessKey("cn-beijing", global.ServerConfig.AliSmsInfo.ApiKey, global.ServerConfig.AliSmsInfo.ApiSecret)
	mobile := "13001350015"
	smsCode := GenerateSmsCode(6)
	if err != nil {
		panic(err)
	}
	request := requests.NewCommonRequest()
	request.Method = "POST"
	request.Scheme = "https"
	request.Domain = "dysmsapi.aliyuncs.com"
	request.Version = "2017-05-25"
	request.ApiName = "SendSms"
	// 直接写,无需在阿里云上配置
	request.QueryParams["RegionId"] = "cn-beijing"
	request.QueryParams["PhoneNumbers"] = mobile
	// 这里要写 签名的名字,注意是名字
	request.QueryParams["SignName"] = "清河个人博客网站"
	// 这里要写模版的 id,注意是 id
	request.QueryParams["TemplateCode"] = "SMS_461975751"
	// 参照你的模版发送请求,注意中间的验证码是可以自定义生成的
	request.QueryParams["TemplateParam"] = "{\"code\":" + smsCode + "}"
	response, err := client.ProcessCommonRequest(request)
	fmt.Println(client.DoAction(request, response))
	if err != nil {
		fmt.Println(err.Error())
	}
	fmt.Printf("response is %#v\n", response)
	
	// 将验证码保存到 redis 以手机号为 key, 以验证码为 value
	rdb := redis.NewClient(&redis.Options{
		Addr: fmt.Sprintf("%s:%d", global.ServerConfig.RedisInfo.Host, global.ServerConfig.RedisInfo.Port),
	})
	rdb.Set(context.Background(), mobile, smsCode, 30*time.Second)
		
	ctx.JSON(http.StatusOK, gin.H{
		"msg": "验证码发送成功",
	})
}

另外,该接口还涉及到 form 表单问题,要求手机号必须填写:

在 form 目录下新建一个 go 文件:form/sms.go

package forms

// 这里要注意 binding 内部的参数不可以加空格
// 请求中需要有 手机号、密码、验证码输入信息、验证码图片信息
type SendSmsForm struct {
	Mobile string `form:"mobile" json:"mobile" binding:"required,mobile"`
	// 这里为了区分开登录和注册的逻辑,包括具体场景下会出现的 找回密码等逻辑,需要添加一个 Type 表单
	Type uint `form:"type" json:"type" binding:"required,oneof=1 2"`
}

之后在 核心逻辑中添加表单验证的代码:

func SendSms(ctx *gin.Context) {
	// 表单验证 要求必须传入手机号和 验证码类型
	sendSmsForm := forms.SendSmsForm{}
	if err := ctx.ShouldBind(&sendSmsForm); err != nil {
		HandleValidatorError(ctx, err)
		return
	}

	client, err := dysmsapi.NewClientWithAccessKey("cn-beijing", global.ServerConfig.AliSmsInfo.ApiKey, global.ServerConfig.AliSmsInfo.ApiSecret)
	smsCode := GenerateSmsCode(6)
    ......

在router/base.go 中添加发送短信验证码的路由:

package router

import (
	"github.com/gin-gonic/gin"
	"mxshop-api/user-web/api"
)

func InitBaseRouter(Router *gin.RouterGroup) {
	BaseRouter := Router.Group("base")
	{
		BaseRouter.GET("captcha", api.GetCaptcha)
		// TODO
		BaseRouter.POST("send_sms", api.SendSms)
	}
}

之后,手机会收到验证码,验证码也会被存储在 redis 中

注册接口

创建核心逻辑的方法:

api/user.go

func Register(ctx *gin.Context) {
	// 配置传入的表单
}

在 forms / user.go 中添加表单验证信息:

type RegisterForm struct {
	Mobile   string `form:"mobile" json:"mobile" binding:"required,mobile"`
	Password string `form:"password" json:"password" binding:"required,min=3,max=10"`
	Code     string `form:"code" json:"code" binding:"required,min=6,max=6"`
}

之后继续编写注册的核心逻辑

api/user.go

func Register(ctx *gin.Context) {
	registerForm := forms.RegisterForm{}
	// 配置传入的表单,进行表单验证
	if err := ctx.ShouldBind(&registerForm); err != nil {
		HandleValidatorError(ctx, err)
		return
	}

	// 进行短信验证码校验
	rdb := redis.NewClient(&redis.Options{
		Addr: fmt.Sprintf("%s:%d", global.ServerConfig.RedisInfo.Host, global.ServerConfig.RedisInfo.Port),
	})
	if value, err := rdb.Get(context.Background(), registerForm.Mobile).Result(); err == redis.Nil {
		zap.S().Debug("key 不存在")
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code": "验证码过期或未发送验证码",
		})
		return
	} else if value != registerForm.Code {
		ctx.JSON(http.StatusBadRequest, gin.H{
			"code": "验证码错误",
		})
		return
	}

	// 用户拨号连接 grpc 服务
	userConn, err := grpc.Dial(fmt.Sprintf("%s:%d", global.ServerConfig.UserSrvInfo.Host, global.ServerConfig.UserSrvInfo.Port), grpc.WithInsecure())
	if err != nil {
		zap.S().Errorw("[Register] 连接用户服务器失败", "msg", err.Error())
	}

	// 生成用户模块的 grpc 接口并调用
	userSrvClient := proto.NewUserClient(userConn)
	user, err := userSrvClient.CreateUser(context.Background(), &proto.CreateUserInfo{
		Nickname: registerForm.Mobile,
		Password: registerForm.Password,
		Mobile:   registerForm.Mobile,
	})
	if err != nil {
		zap.S().Errorf("[Register] 创建用户 失败")
		HandleGrpcErrorToHttp(err, ctx)
		return
	}

	// 注册成功,自动登录,生成登录的ToKEN
	// 登录成功,生成TOKEN
	j := middlewares.NewJWT() // 获得签名
	// 构建传递的信息以及签名信息
	claims := models.CustomClaims{
		ID:          uint(user.Id),
		NickName:    user.NickName,
		AuthorityID: uint(user.Role),
		StandardClaims: jwt.StandardClaims{ // 签名相关信息
			NotBefore: time.Now().Unix(),               // 签名生效时间:现在
			ExpiresAt: time.Now().Unix() + 60*60*24*30, // 签名过期时间,从现在开始一个月
			Issuer:    "BaiLu",                         // 签名 对象 (公司)
		},
	}
	// 真正创建 TOKEN:
	token, err := j.CreateToken(claims)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{
			"msg": "TOKEN生成失败",
		})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"id":         user.Id,
		"nick_name":  user.NickName,
		"token":      token,
		"expired_at": (time.Now().Unix() + 60*60*24*30) * 1000,
	})

}

将 Register 添加到 Router 中

router/user.go

func InitUserRouter(Router *gin.RouterGroup) {
	// 这样就需要 /user/list 才可以进行访问了
	UserRouter := Router.Group("user")
	{
		// 在这里添加拦截器的作用响应位置
		UserRouter.GET("list", middlewares.JWTAuth(), middlewares.IsAdminAuth(), api.GetUserList)
		//UserRouter.GET("list", api.GetUserList)
		UserRouter.POST("pwd_login", api.PassWordLogin)
		UserRouter.POST("register", api.Register)
	}
}

你可能感兴趣的:(Go,golang,redis,开发语言)