• 15、用户web层服务(三)


    一、图形验证码

    1 - 生成图片验证码

    package api
    
    import (
    	"net/http"
    
    	"github.com/gin-gonic/gin"
    	"github.com/mojocn/base64Captcha"
    	"go.uber.org/zap"
    )
    
    var store = base64Captcha.DefaultMemStore
    
    func GetCaptcha(ctx *gin.Context) {
    	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("生成验证码错误,: ", err.Error())
    		ctx.JSON(http.StatusInternalServerError, gin.H{
    			"msg": "生成验证码错误",
    		})
    		return
    	}
    	ctx.JSON(http.StatusOK, gin.H{
    		"captchaId": id,
    		"picPath":   b64s,
    	})
    }
    
    
    • 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
    • user_web\router\router_base.go
    package router
    
    import (
    	"github.com/gin-gonic/gin"
    
    	"web_api/user_web/api"
    )
    
    func InitBaseRouter(Router *gin.RouterGroup) {
    	BaseRouter := Router.Group("base")
    	{
    		BaseRouter.GET("captcha", api.GetCaptcha)
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • user_web\initialize\init_router.go
    package initialize
    
    import (
    	"github.com/gin-gonic/gin"
    
    	"web_api/user_web/middlewares"
    	"web_api/user_web/router"
    )
    
    func Routers() *gin.Engine {
    	Router := gin.Default()
    
    	//配置跨域
    	Router.Use(middlewares.Cors())
    	ApiGroup := Router.Group("/u/v1")
    
    	router.InitUserRouter(ApiGroup)
    	router.InitBaseRouter(ApiGroup)
    	return Router
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

    2 - 登录添加图片验证码

    • user_web\forms\form_user.go
    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"`
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • user_web\api\api_user.go
    func PassWordLogin(c *gin.Context) {
    	//表单验证
    	passwordLoginForm := forms.PassWordLoginForm{}
    	if err := c.ShouldBind(&passwordLoginForm); err != nil {
    		HandleValidatorError(c, err)
    		return
    	}
    
    	if store.Verify(passwordLoginForm.CaptchaId, passwordLoginForm.Captcha, false) {
    		c.JSON(http.StatusBadRequest, gin.H{
    			"captcha": "验证码错误",
    		})
    		return
    	}
    	//...省略
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述


    二、用户注册

    1 - docker安装redis

    2 - 阿里云短信验证码

    • user_web\forms\form_sms.go
    package forms
    
    type SendSmsForm struct {
    	Mobile string `form:"mobile" json:"mobile" binding:"required,mobile"` // 手机号码格式有规范可寻, 自定义validator
    	Type   uint   `form:"type" json:"type" binding:"required,oneof=1 2"`  // 注册发送短信验证码和动态验证码登录发送验证码
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • user_web\router\router_base.go
    package router
    
    import (
    	"github.com/gin-gonic/gin"
    
    	"web_api/user_web/api"
    )
    
    func InitBaseRouter(Router *gin.RouterGroup) {
    	BaseRouter := Router.Group("base")
    	{
    		BaseRouter.GET("captcha", api.GetCaptcha)
    		BaseRouter.POST("send_sms", api.SendSms)
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • user_web\api\sms.go
    package api
    
    import (
    	"context"
    	"fmt"
    	"math/rand"
    	"net/http"
    	"strings"
    	"time"
    	"web_api/user_web/forms"
    
    	"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"
    
    	"web_api/user_web/global"
    )
    
    func GenerateSmsCode(witdh int) string {
    	//生成width长度的短信验证码
    
    	numeric := [10]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
    	r := len(numeric)
    	rand.Seed(time.Now().UnixNano())
    
    	var sb strings.Builder
    	for i := 0; i < witdh; 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.ApiSecrect)
    	if err != nil {
    		panic(err)
    	}
    	smsCode := GenerateSmsCode(6)
    	request := requests.NewCommonRequest()
    	request.Method = "POST"
    	request.Scheme = "https" // https | http
    	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"] = "慕学在线"                            //阿里云验证过的项目名 自己设置
    	request.QueryParams["TemplateCode"] = "SMS_181850725"               //阿里云的短信模板号 自己设置
    	request.QueryParams["TemplateParam"] = "{\"code\":" + smsCode + "}" //短信模板中的验证码内容 自己生成   之前试过直接返回,但是失败,加上code成功。
    	response, err := client.ProcessCommonRequest(request)
    	fmt.Print(client.DoAction(request, response))
    	if err != nil {
    		fmt.Print(err.Error())
    	}
    	//将验证码保存起来 - redis
    	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": "发送成功",
    	})
    }
    
    
    • 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
    • yaml:隐私原因key和secret未配置
    //user_web\config_debug.yaml
    //user_web\config_pro.yaml
    name: 'user-web'
    port: '8081'
    user_srv:
      host: '127.0.0.1'
      port: '50051'
    jwt:
      key: 'VYLDYq3&hGWjWqF$K1ih'
    sms:
      key: ''
      secrect: ''
      expire: 300
    redis:
      host: '192.168.124.51'
      port: '6379'
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    三、用户注册接口

    • user_web\forms\form_user.go
    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"`
    }
    
    type RegisterForm struct {
    	Mobile   string `form:"mobile" json:"mobile" binding:"required,mobile"` //手机号码格式有规范可寻, 自定义validator
    	PassWord string `form:"password" json:"password" binding:"required,min=3,max=20"`
    	Code     string `form:"code" json:"code" binding:"required,min=6,max=6"`
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • user_web\api\api_user.go
    func Register(c *gin.Context) {
    	//用户注册
    	registerForm := forms.RegisterForm{}
    	if err := c.ShouldBind(&registerForm); err != nil {
    		HandleValidatorError(c, err)
    		return
    	}
    
    	//验证码
    	rdb := redis.NewClient(&redis.Options{
    		Addr: fmt.Sprintf("%s:%d", global.ServerConfig.RedisInfo.Host, global.ServerConfig.RedisInfo.Port),
    	})
    	value, err := rdb.Get(registerForm.Mobile).Result()
    	if err == redis.Nil {
    		c.JSON(http.StatusBadRequest, gin.H{
    			"code": "验证码错误",
    		})
    		return
    	} else {
    		if value != registerForm.Code {
    			c.JSON(http.StatusBadRequest, gin.H{
    				"code": "验证码错误",
    			})
    			return
    		}
    	}
    
    	user, err := global.UserSrvClient.CreateUser(context.Background(), &proto.CreateUserInfo{
    		NickName: registerForm.Mobile,
    		PassWord: registerForm.PassWord,
    		Mobile:   registerForm.Mobile,
    	})
    
    	if err != nil {
    		zap.S().Errorf("[Register] 查询 【新建用户失败】失败: %s", err.Error())
    		HandleGrpcErrorToHttp(err, c)
    		return
    	}
    
    	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, //30天过期
    			Issuer:    "imooc",
    		},
    	}
    	token, err := j.CreateToken(claims)
    	if err != nil {
    		c.JSON(http.StatusInternalServerError, gin.H{
    			"msg": "生成token失败",
    		})
    		return
    	}
    
    	c.JSON(http.StatusOK, gin.H{
    		"id":         user.Id,
    		"nick_name":  user.NickName,
    		"token":      token,
    		"expired_at": (time.Now().Unix() + 60*60*24*30) * 1000,
    	})
    }
    
    • 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
    • user_web\router\router_user.go
    package router
    
    import (
    	"web_api/user_web/api"
    	"web_api/user_web/middlewares"
    
    	"github.com/gin-gonic/gin"
    	"go.uber.org/zap"
    )
    
    func InitUserRouter(Router *gin.RouterGroup) {
    	UserRouter := Router.Group("user")
    	//UserRouter := Router.Group("user").Use(middlewares.JWTAuth()) //给整个user都添加登录验证
    	zap.S().Info("配置用户相关的url")
    	{
    		UserRouter.GET("list", middlewares.JWTAuth(), middlewares.IsAdminAuth(), api.GetUserList)
    		UserRouter.POST("pwd_login", api.PassWordLogin)
    		UserRouter.POST("register", api.Register)
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • YApi配置注册接口
      在这里插入图片描述

    四、完整源码

    mxshop_srvsV5.0.rar

  • 相关阅读:
    Mysql两道英文上机练习
    linux yum源被禁用,yum源管理
    IO流再回顾,深入理解序列化和反序列化
    我有一个朋友,分享给我的字节跳动测试开发真题
    Docker安装SQL Server 2022
    太空射击第09课:精灵动画
    camx 主要接口
    移植RT-Thread Nano到STM32F407ZGT6上运行
    【Python开发】一文详解Flask-Login
    基础算法---差分
  • 原文地址:https://blog.csdn.net/qq23001186/article/details/126023218