forked from YaoApp/yao
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
317 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ package main | |
|
||
import ( | ||
"github.com/yaoapp/xiang/cmd" | ||
_ "github.com/yaoapp/xiang/user" | ||
) | ||
|
||
// 主程序 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
package user | ||
|
||
import ( | ||
"errors" | ||
"image/color" | ||
|
||
"github.com/mojocn/base64Captcha" | ||
"github.com/yaoapp/kun/exception" | ||
) | ||
|
||
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", | ||
} | ||
} | ||
|
||
// MakeCaptcha 制作验证码 | ||
func MakeCaptcha(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 := background(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() | ||
} | ||
return id, content | ||
} | ||
|
||
// ValidateCaptcha 校验验证码 | ||
func ValidateCaptcha(id string, value string) bool { | ||
return captchaStore.Verify(id, value, true) | ||
} | ||
|
||
func background(s string) *color.RGBA { | ||
if s == "" { | ||
s = "#555555" | ||
} | ||
bg, err := parseHexColorFast(s) | ||
if err != nil { | ||
exception.New("背景色格式错误 %s", 400, s).Throw() | ||
} | ||
return &bg | ||
} | ||
|
||
func parseHexColorFast(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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package user | ||
|
||
import ( | ||
"github.com/yaoapp/gou" | ||
"github.com/yaoapp/kun/any" | ||
"github.com/yaoapp/kun/maps" | ||
) | ||
|
||
func init() { | ||
// 注册处理器 | ||
gou.RegisterProcessHandler("xiang.user.Captcha", ProcessCaptcha) | ||
} | ||
|
||
// ProcessLogin xiang.user.Login 用户登录 | ||
func ProcessLogin(process *gou.Process) interface{} { | ||
return nil | ||
} | ||
|
||
// ProcessCaptcha xiang.user.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 := MakeCaptcha(option) | ||
return maps.Map{ | ||
"id": id, | ||
"content": content, | ||
} | ||
} | ||
|
||
// ProcessToken xiang.user.Token 使用 Key & Secret 换取 Token | ||
func ProcessToken(process *gou.Process) interface{} { | ||
return nil | ||
} | ||
|
||
// ProcessTokenRefresh xiang.user.TokenRefresh 刷新Token | ||
func ProcessTokenRefresh(process *gou.Process) interface{} { | ||
return nil | ||
} | ||
|
||
// ProcessInfo xiang.user.Info 读取当前用户资料 | ||
func ProcessInfo(process *gou.Process) interface{} { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
package user |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package user | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestCaptcha(t *testing.T) { | ||
id, content := MakeCaptcha(CaptchaOption{ | ||
Type: "audio", | ||
Width: 240, | ||
Height: 80, | ||
Length: 4, | ||
Lang: "zh", | ||
}) | ||
assert.IsType(t, "string", id) | ||
assert.IsType(t, "string", content) | ||
captchaStore.Get(id, false) | ||
assert.True(t, ValidateCaptcha(id, captchaStore.Get(id, false))) | ||
|
||
id, content = MakeCaptcha(CaptchaOption{ | ||
Type: "math", | ||
Width: 240, | ||
Height: 80, | ||
Length: 4, | ||
Lang: "zh", | ||
}) | ||
assert.IsType(t, "string", id) | ||
assert.IsType(t, "string", content) | ||
captchaStore.Get(id, false) | ||
assert.True(t, ValidateCaptcha(id, captchaStore.Get(id, false))) | ||
|
||
id, content = MakeCaptcha(CaptchaOption{ | ||
Type: "digit", | ||
Width: 240, | ||
Height: 80, | ||
Length: 4, | ||
Lang: "zh", | ||
}) | ||
assert.IsType(t, "string", id) | ||
assert.IsType(t, "string", content) | ||
captchaStore.Get(id, false) | ||
assert.True(t, ValidateCaptcha(id, captchaStore.Get(id, false))) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
{ | ||
"name": "系统用户接口", | ||
"version": "1.0.0", | ||
"description": "系统用户API", | ||
"group": "xiang/user", | ||
"guard": "bearer-jwt", | ||
"paths": [ | ||
{ | ||
"path": "/captcha", | ||
"method": "GET", | ||
"guard": "-", | ||
"process": "xiang.user.Captcha", | ||
"in": [":query"], | ||
"out": { | ||
"status": 200, | ||
"type": "application/json" | ||
} | ||
}, | ||
{ | ||
"path": "/login", | ||
"method": "POST", | ||
"guard": "-", | ||
"process": "xiang.user.Login", | ||
"in": ["$payload.email", "$payload.password", "$payload.captcha"], | ||
"out": { | ||
"status": 200, | ||
"type": "application/json" | ||
} | ||
}, | ||
{ | ||
"path": "/token", | ||
"method": "POST", | ||
"guard": "-", | ||
"process": "xiang.user.Token", | ||
"in": ["$payload.key", "$payload.secret"], | ||
"out": { | ||
"status": 200, | ||
"type": "application/json" | ||
} | ||
}, | ||
{ | ||
"path": "/info", | ||
"method": "GET", | ||
"process": "xiang.user.Info", | ||
"in": [], | ||
"out": { | ||
"status": 200, | ||
"type": "application/json" | ||
} | ||
}, | ||
{ | ||
"path": "/token/refresh", | ||
"method": "GET", | ||
"process": "xiang.user.TokenRefresh", | ||
"in": [], | ||
"out": { | ||
"status": 200, | ||
"type": "application/json" | ||
} | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters