验证码简单实现

验证码添加 expire 超时时间
swag 添加 验证码测试
This commit is contained in:
Shikong 2022-10-25 11:40:24 +08:00
parent a4a9b27e5a
commit 72fb03ddbf
11 changed files with 411 additions and 18 deletions

View File

@ -16,7 +16,7 @@ func reloadCaptcha(c *config.BasicConfig, redis *redis.Client) {
NoiseCount: c.Captcha.NoiseCount,
Fonts: []string{
"SourceHanSansCN-VF-2.otf",
"wqy-microhei.ttc",
},
ShowLineOptions: c.Captcha.ShowLineOptions,
Length: c.Captcha.Length,

View File

@ -66,4 +66,6 @@ type CaptchaConfig struct {
Source string `yaml:"source"`
//BgColor captcha image background color (optional)
BgColor *color.RGBA `yaml:"bgColor"`
//Expire 失效时间 (秒)
Expire int64 `json:"expired"`
}

View File

@ -40,4 +40,5 @@ captcha:
width: 200
noiseCount: 100
showLineOptions: 4
source: 1234567890qwertyuioplkjhgfdsazxcvbnm
source: 1234567890qwertyuioplkjhgfdsazxcvbnm
expire: 300

View File

@ -3,9 +3,13 @@ package test
import (
"github.com/gofiber/fiber/v2"
"gofiber.study.skcks.cn/common/errorx"
"gofiber.study.skcks.cn/common/logger"
"gofiber.study.skcks.cn/common/response"
"gofiber.study.skcks.cn/controller/types"
"gofiber.study.skcks.cn/global"
"gofiber.study.skcks.cn/model/dto"
"gofiber.study.skcks.cn/model/vo"
"time"
)
type Controller struct {
@ -120,8 +124,18 @@ func (c *Controller) NanoIdTest() {
})
}
func (c *Controller) GetCaptcha() {
c.Router.Add(fiber.MethodGet, "/getCaptcha", func(ctx *fiber.Ctx) error {
// GetCaptchaTest 验证码 生成测试
//
// @Summary 验证码 生成测试
// @Description 验证码 生成测试
// @Tags Test
// @Accept json
// @Produce json
// @Success 200 {object} response.Response{data=vo.Captcha}
// @Failure default {object} errorx.CodeErrorResponse
// @Router /test/captcha/get [get]
func (c *Controller) GetCaptchaTest() {
c.Router.Add(fiber.MethodGet, "/captcha/get", func(ctx *fiber.Ctx) error {
id, content, answer := global.Captcha.Driver.GenerateIdQuestionAnswer()
item, err := global.Captcha.Driver.DrawCaptcha(content)
err = global.Captcha.Store.Set(id, answer)
@ -129,23 +143,36 @@ func (c *Controller) GetCaptcha() {
return ctx.JSON(errorx.NewDefaultError("验证码生成失败"))
}
type resp struct {
Id string `json:"id"`
Data string `json:"captcha"`
}
return ctx.JSON(response.NewResponse(resp{
id,
item.EncodeB64string(),
return ctx.JSON(response.NewResponse(vo.Captcha{
Id: id,
Base64: item.EncodeB64string(),
Expire: time.Now().Add(time.Duration(global.Config.Captcha.Expire) * time.Second).Unix(),
}))
})
}
func (c *Controller) VerifyCaptcha() {
c.Router.Add(fiber.MethodPost, "/verifyCaptcha", func(ctx *fiber.Ctx) error {
id := ctx.Query("id")
captcha := ctx.Query("captcha")
// VerifyCaptchaTest 验证码 验证测试
//
// @Summary 验证码 验证测试
// @Description 验证码 验证测试
// @Tags Test
// @Accept json
// @Produce json
// @Param vo body dto.VerifyCaptcha true "验证码验证"
// @Success 200 {object} response.Response{data=string}
// @Failure default {object} errorx.CodeErrorResponse
// @Router /test/captcha/verify [post]
func (c *Controller) VerifyCaptchaTest() {
c.Router.Add(fiber.MethodPost, "/captcha/verify", func(ctx *fiber.Ctx) error {
verifyCaptcha := &dto.VerifyCaptcha{}
verify := global.Captcha.Verify(id, captcha, true)
if err := errorx.ParseError(ctx.BodyParser(verifyCaptcha)); err != nil {
return ctx.JSON(err)
}
logger.Log.Debugf("verifyCaptcha %#v", verifyCaptcha)
verify := global.Captcha.Store.Verify(verifyCaptcha.Id, verifyCaptcha.Captcha, true)
if !verify {
return ctx.JSON(errorx.NewDefaultError("验证码错误"))
}

View File

@ -442,6 +442,99 @@ const docTemplate = `{
}
}
},
"/test/captcha/get": {
"get": {
"description": "验证码 生成测试",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Test"
],
"summary": "验证码 生成测试",
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/vo.Captcha"
}
}
}
]
}
},
"default": {
"description": "",
"schema": {
"$ref": "#/definitions/errorx.CodeErrorResponse"
}
}
}
}
},
"/test/captcha/verify": {
"post": {
"description": "验证码 验证测试",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Test"
],
"summary": "验证码 验证测试",
"parameters": [
{
"description": "验证码验证",
"name": "vo",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.VerifyCaptcha"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"type": "string"
}
}
}
]
}
},
"default": {
"description": "",
"schema": {
"$ref": "#/definitions/errorx.CodeErrorResponse"
}
}
}
}
},
"/test/jwt": {
"get": {
"description": "jwt token 解析测试",
@ -683,6 +776,10 @@ const docTemplate = `{
"definitions": {
"dto.Login": {
"type": "object",
"required": [
"account",
"password"
],
"properties": {
"account": {
"type": "string",
@ -696,6 +793,9 @@ const docTemplate = `{
},
"dto.RefreshToken": {
"type": "object",
"required": [
"refreshToken"
],
"properties": {
"refreshToken": {
"type": "string",
@ -703,6 +803,19 @@ const docTemplate = `{
}
}
},
"dto.VerifyCaptcha": {
"type": "object",
"properties": {
"captcha": {
"type": "string",
"example": "abcde"
},
"id": {
"type": "string",
"example": "abcdefg123456"
}
}
},
"errorx.CodeErrorResponse": {
"type": "object",
"properties": {
@ -749,6 +862,9 @@ const docTemplate = `{
},
"id": {
"type": "string"
},
"identify": {
"type": "string"
}
}
},
@ -804,6 +920,21 @@ const docTemplate = `{
}
}
},
"vo.Captcha": {
"type": "object",
"properties": {
"base64": {
"description": "验证码图片 base64",
"type": "string",
"example": "data:image/png;base64,iVBO..."
},
"id": {
"description": "验证码 id",
"type": "string",
"example": "abcdefg123456"
}
}
},
"vo.Login": {
"type": "object",
"properties": {

View File

@ -434,6 +434,99 @@
}
}
},
"/test/captcha/get": {
"get": {
"description": "验证码 生成测试",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Test"
],
"summary": "验证码 生成测试",
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/vo.Captcha"
}
}
}
]
}
},
"default": {
"description": "",
"schema": {
"$ref": "#/definitions/errorx.CodeErrorResponse"
}
}
}
}
},
"/test/captcha/verify": {
"post": {
"description": "验证码 验证测试",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Test"
],
"summary": "验证码 验证测试",
"parameters": [
{
"description": "验证码验证",
"name": "vo",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.VerifyCaptcha"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"type": "string"
}
}
}
]
}
},
"default": {
"description": "",
"schema": {
"$ref": "#/definitions/errorx.CodeErrorResponse"
}
}
}
}
},
"/test/jwt": {
"get": {
"description": "jwt token 解析测试",
@ -675,6 +768,10 @@
"definitions": {
"dto.Login": {
"type": "object",
"required": [
"account",
"password"
],
"properties": {
"account": {
"type": "string",
@ -688,6 +785,9 @@
},
"dto.RefreshToken": {
"type": "object",
"required": [
"refreshToken"
],
"properties": {
"refreshToken": {
"type": "string",
@ -695,6 +795,19 @@
}
}
},
"dto.VerifyCaptcha": {
"type": "object",
"properties": {
"captcha": {
"type": "string",
"example": "abcde"
},
"id": {
"type": "string",
"example": "abcdefg123456"
}
}
},
"errorx.CodeErrorResponse": {
"type": "object",
"properties": {
@ -741,6 +854,9 @@
},
"id": {
"type": "string"
},
"identify": {
"type": "string"
}
}
},
@ -796,6 +912,21 @@
}
}
},
"vo.Captcha": {
"type": "object",
"properties": {
"base64": {
"description": "验证码图片 base64",
"type": "string",
"example": "data:image/png;base64,iVBO..."
},
"id": {
"description": "验证码 id",
"type": "string",
"example": "abcdefg123456"
}
}
},
"vo.Login": {
"type": "object",
"properties": {

View File

@ -8,12 +8,26 @@ definitions:
password:
example: "12341234"
type: string
required:
- account
- password
type: object
dto.RefreshToken:
properties:
refreshToken:
example: 0123456789ABCDEFG
type: string
required:
- refreshToken
type: object
dto.VerifyCaptcha:
properties:
captcha:
example: abcde
type: string
id:
example: abcdefg123456
type: string
type: object
errorx.CodeErrorResponse:
properties:
@ -48,6 +62,8 @@ definitions:
type: string
id:
type: string
identify:
type: string
type: object
models.User:
properties:
@ -84,6 +100,17 @@ definitions:
example: OK
type: string
type: object
vo.Captcha:
properties:
base64:
description: 验证码图片 base64
example: data:image/png;base64,iVBO...
type: string
id:
description: 验证码 id
example: abcdefg123456
type: string
type: object
vo.Login:
properties:
refreshToken:
@ -366,6 +393,61 @@ paths:
summary: 获取所有路由
tags:
- Routes
/test/captcha/get:
get:
consumes:
- application/json
description: 验证码 生成测试
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/vo.Captcha'
type: object
default:
description: ""
schema:
$ref: '#/definitions/errorx.CodeErrorResponse'
summary: 验证码 生成测试
tags:
- Test
/test/captcha/verify:
post:
consumes:
- application/json
description: 验证码 验证测试
parameters:
- description: 验证码验证
in: body
name: vo
required: true
schema:
$ref: '#/definitions/dto.VerifyCaptcha'
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
type: string
type: object
default:
description: ""
schema:
$ref: '#/definitions/errorx.CodeErrorResponse'
summary: 验证码 验证测试
tags:
- Test
/test/jwt:
get:
consumes:

Binary file not shown.

View File

@ -28,7 +28,7 @@ func NewCaptchaStore(redis *redis.Client) *CaptchaStore {
}
func (c *CaptchaStore) Set(id string, value string) error {
return c.Store.SetEX(c.Ctx, CaptchaPrefix+CaptchaSeparator+id, value, 180*time.Second).Err()
return c.Store.SetEX(c.Ctx, CaptchaPrefix+CaptchaSeparator+id, value, time.Duration(Config.Captcha.Expire)*time.Second).Err()
}
func (c *CaptchaStore) Get(id string, clear bool) string {
@ -45,6 +45,6 @@ func (c *CaptchaStore) Get(id string, clear bool) string {
}
func (c *CaptchaStore) Verify(id, answer string, clear bool) (match bool) {
match = strings.EqualFold(c.Get(id, clear), answer)
match = strings.EqualFold(c.Get(id, clear), strings.TrimSpace(answer))
return
}

9
model/dto/captcha.go Normal file
View File

@ -0,0 +1,9 @@
package dto
// VerifyCaptcha
// @Param id body string true "验证码 id"
// @Param captcha body string true "验证码"
type VerifyCaptcha struct {
Id string `json:"id" example:"abcdefg123456"`
Captcha string `json:"captcha" example:"abcde"`
}

10
model/vo/captcha.go Normal file
View File

@ -0,0 +1,10 @@
package vo
type Captcha struct {
// 验证码 id
Id string `json:"id" example:"abcdefg123456"`
// 验证码图片 base64
Base64 string `json:"base64" example:"data:image/png;base64,iVBO..."`
// 过期时间 unix
Expire int64 `json:"expire" example:"10000000"`
}