captcha在gin+VUE项目下的使用方式

之前在项目中,一直使用VUE前端的图片验证码。前几天看到文章,说前端验证容易被绕过,那就准备使用后端验证吧。

用golang就选择github.com/dchest/captcha了,折腾一番后,要点记录如下:

控制器:

package controllers

import (

    "bytes"

    "log"

    "net/http"

    "strconv"

    "strings"

    "time"

    "utils"

    "github.com/dchest/captcha"

    "github.com/gin-gonic/gin"

)

type CheckCodeController struct {

}

/***

*后端图形码验证

*/

func (serviceCheckCode *CheckCodeController) VerifyCode(c *gin.Context) {

    captchaId := c.Query("captchaId")

    pngCode := c.Query("pngCode")

    if captcha.VerifyString(captchaId, pngCode) {

        result := utils.ResultSuccess()   //自己写的用于规范一般状态码传递的package

        c.JSON(http.StatusOK, gin.H{

            "data": result,

        })

    } else {

        result := utils.ResultFailue()

        result.Msg = "图形验证码错误"

        c.JSON(http.StatusOK, gin.H{

            "data": result,

        })

    }

}

/***

刷新验证码,也作为初次获取验证码使用

*/

func (serviceCheckCode *CheckCodeController) ReloadVerifyCode(c *gin.Context) {

    id := captcha.NewLen(4)    //一般用4位数字

    result := utils.ResultSuccess()

    result.Msg = id    //偷懒一下,直接用这个来传递captchaId到前端

    c.JSON(http.StatusOK, gin.H{

        "data": result,

    })

}

/**

显示图形验证码
因为要传递图片,所以要对Header做一些设置

*/

func (serviceCheckCode *CheckCodeController) GenVerifyCode(c *gin.Context) {

    c.Writer.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")

    c.Writer.Header().Set("Pragma", "no-cache")

    c.Writer.Header().Set("Expires", "0")

    c.Writer.Header().Set("Content-Type", "image/png")


    id := c.Param("captchaId")

    id = strings.Replace(id, "/", "", 1)


    var content bytes.Buffer

    captcha.WriteImage(&content, id, 100, 50)  //4位验证码,宽100,高50最清晰

    http.ServeContent(c.Writer, c.Request, id+".png", time.Time{}, bytes.NewReader(content.Bytes()))

    return

}

路由:

checkCodeRoute := router.Group("/check-code")
        {
            checkCodeController := new(controllers.CheckCodeController)
            //刷新图形验证码
            checkCodeRoute.GET("refresh.html", checkCodeController.ReloadVerifyCode)
            //获取图形验证码
            checkCodeRoute.GET("/show/*captchaId", checkCodeController.GenVerifyCode)
            //验证图形码
            checkCodeRoute.GET("/verify", checkCodeController.VerifyCode)
        }

前端:

<template>
  <div>
  <div>
      <el-input v-model="pngCode" placeholder="请输入图片验证码" style="width: 120px;"></el-input>
        <span @click="getCaptchaImgUrl" class="box-verify"><img id="captchaIdImg" :src="captchaImgUrl" /></span>
      <el-button @click="verifyCaptcha">验证</el-button>
    </div>
  </div>
</template>

<script>
 export default {
  data() {
      return {
        captchaId: '',
        captchaImgUrl: '',
        pngCode: ''
      }
    },
    methods: {
      getCaptchaImgUrl() {
        this.axios.get('/check-code/refresh.html', {})
        .then(res => {
          this.captchaId = res.data.data.Msg
          let url = window.location.href
          let host = window.location.host
          let n = host.indexOf(":", 0)
          let k = url.indexOf(host.slice(0,n), 0)
          //这里的端口8000是后端gin的端口
          this.captchaImgUrl = url.slice(0,k) + host.slice(0,n) + ':8000/web/check-code/show/' + res.data.data.Msg
        }).catch(err => {
          console.log(err)
        })
        // console.log(this.captchaImgUrl)
      }, 
      verifyCaptcha() {
        // 因为显示图片验证码的时候, header被改成了'Content-Type': 'image/png',所以
        this.axios({
          methods:"GET",
          url:'/check-code/verify', 
          headers:{
            'Content-Type': 'application/x-www-form-urlencoded'
          },
          params: {
            "captchaId": this.captchaId,
            "pngCode": this.pngCode
          }
        }).then(res => {
          if (res.data.data.Code == 200 ) {
            console.log(res.data.data.Msg)
          } else {
            console.log(res.data.data.Msg)
          }
        }).catch(err => {
          console.log(err)
        })
      }
    },
    mounted() {
      this.getCaptchaImgUrl()
    }
  }
</script>

<!-- 样式 -->
<style>
  .box-verify img{
    vertical-align: middle;
  }
</style>

大功告成!

上一篇:SOFAMesh解决方案x-protocol介绍系列(1) : DNS通用寻址方案


下一篇:SecureCRT连接Linux主机时,如何更改连接方式为xterm