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, } }