173 lines
3.8 KiB
Go
173 lines
3.8 KiB
Go
package helper
|
|
|
|
import (
|
|
"errors"
|
|
"image/color"
|
|
|
|
"github.com/mojocn/base64Captcha"
|
|
"github.com/yaoapp/gou"
|
|
"github.com/yaoapp/kun/any"
|
|
"github.com/yaoapp/kun/exception"
|
|
"github.com/yaoapp/kun/log"
|
|
"github.com/yaoapp/kun/maps"
|
|
)
|
|
|
|
var captchaStore = base64Captcha.DefaultMemStore
|
|
|
|
// CaptchaOption 验证码配置
|
|
type CaptchaOption struct {
|
|
Type string
|
|
Height int
|
|
Width int
|
|
Length int
|
|
Lang string
|
|
Background string
|
|
}
|
|
|
|
// NewCaptchaOption 创建验证码配置
|
|
func NewCaptchaOption() CaptchaOption {
|
|
return CaptchaOption{
|
|
Width: 240,
|
|
Height: 80,
|
|
Length: 4,
|
|
Lang: "zh",
|
|
Background: "#FFFFFF",
|
|
}
|
|
}
|
|
|
|
// CaptchaMake 制作验证码
|
|
func CaptchaMake(option CaptchaOption) (string, string) {
|
|
|
|
if option.Width == 0 {
|
|
option.Width = 240
|
|
}
|
|
|
|
if option.Height == 0 {
|
|
option.Width = 80
|
|
}
|
|
|
|
if option.Length == 0 {
|
|
option.Length = 4
|
|
}
|
|
|
|
if option.Lang == "" {
|
|
option.Lang = "zh"
|
|
}
|
|
|
|
var driver base64Captcha.Driver
|
|
switch option.Type {
|
|
case "audio":
|
|
driver = base64Captcha.NewDriverAudio(option.Length, option.Lang)
|
|
break
|
|
case "math":
|
|
background := captchaBackground(option.Background)
|
|
driver = base64Captcha.NewDriverMath(
|
|
option.Height, option.Width, 3,
|
|
base64Captcha.OptionShowHollowLine, background,
|
|
base64Captcha.DefaultEmbeddedFonts, []string{},
|
|
)
|
|
break
|
|
default:
|
|
driver = base64Captcha.NewDriverDigit(
|
|
option.Height, option.Width, 5,
|
|
0.7, 80,
|
|
)
|
|
break
|
|
}
|
|
|
|
c := base64Captcha.NewCaptcha(driver, captchaStore)
|
|
id, content, err := c.Generate()
|
|
if err != nil {
|
|
exception.New("生成验证码出错 %s", 500, err).Throw()
|
|
}
|
|
|
|
// 打印日志
|
|
log.Debug("图形/音频 ID:%s 验证码:%s", id, captchaStore.Get(id, false))
|
|
|
|
return id, content
|
|
}
|
|
|
|
// CaptchaValidate 校验验证码
|
|
func CaptchaValidate(id string, value string) bool {
|
|
return captchaStore.Verify(id, value, true)
|
|
}
|
|
|
|
func captchaBackground(s string) *color.RGBA {
|
|
if s == "" {
|
|
s = "#555555"
|
|
}
|
|
bg, err := captchaParseHexColorFast(s)
|
|
if err != nil {
|
|
exception.New("背景色格式错误 %s", 400, s).Throw()
|
|
}
|
|
return &bg
|
|
}
|
|
|
|
func captchaParseHexColorFast(s string) (c color.RGBA, err error) {
|
|
c.A = 0xff
|
|
|
|
if s[0] != '#' {
|
|
return c, errors.New("invalid format")
|
|
}
|
|
|
|
hexToByte := func(b byte) byte {
|
|
switch {
|
|
case b >= '0' && b <= '9':
|
|
return b - '0'
|
|
case b >= 'a' && b <= 'f':
|
|
return b - 'a' + 10
|
|
case b >= 'A' && b <= 'F':
|
|
return b - 'A' + 10
|
|
}
|
|
err = errors.New("invalid format")
|
|
return 0
|
|
}
|
|
|
|
switch len(s) {
|
|
case 7:
|
|
c.R = hexToByte(s[1])<<4 + hexToByte(s[2])
|
|
c.G = hexToByte(s[3])<<4 + hexToByte(s[4])
|
|
c.B = hexToByte(s[5])<<4 + hexToByte(s[6])
|
|
case 4:
|
|
c.R = hexToByte(s[1]) * 17
|
|
c.G = hexToByte(s[2]) * 17
|
|
c.B = hexToByte(s[3]) * 17
|
|
default:
|
|
err = errors.New("invalid format")
|
|
}
|
|
return
|
|
}
|
|
|
|
// ProcessCaptchaValidate xiang.helper.CaptchaValidate 校验图形/音频验证码
|
|
func ProcessCaptchaValidate(process *gou.Process) interface{} {
|
|
process.ValidateArgNums(2)
|
|
id := process.ArgsString(0)
|
|
code := process.ArgsString(1)
|
|
if code == "" {
|
|
exception.New("请输入验证码", 400).Throw()
|
|
return false
|
|
}
|
|
if !CaptchaValidate(id, code) {
|
|
exception.New("验证码不正确", 400).Throw()
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// ProcessCaptcha xiang.helper.Captcha 校验图形/音频验证码
|
|
func ProcessCaptcha(process *gou.Process) interface{} {
|
|
process.ValidateArgNums(1)
|
|
option := CaptchaOption{
|
|
Width: any.Of(process.ArgsURLValue(0, "width", "240")).CInt(),
|
|
Height: any.Of(process.ArgsURLValue(0, "height", "80")).CInt(),
|
|
Length: any.Of(process.ArgsURLValue(0, "height", "4")).CInt(),
|
|
Type: process.ArgsURLValue(0, "type", "math"),
|
|
Background: process.ArgsURLValue(0, "background", "#FFFFFF"),
|
|
Lang: process.ArgsURLValue(0, "lang", "zh"),
|
|
}
|
|
id, content := CaptchaMake(option)
|
|
return maps.Map{
|
|
"id": id,
|
|
"content": content,
|
|
}
|
|
}
|