Ver Fonte

完善图片验证码接口,添加短信验证码接口,添加验证码校验接口

wuww há 6 anos atrás
pai
commit
8f286d97dd
3 ficheiros alterados com 255 adições e 20 exclusões
  1. 73 20
      controllers/partial/CaptchaController.go
  2. 24 0
      light-apiengine.xml
  3. 158 0
      utils/captcha_util.go

+ 73 - 20
controllers/partial/CaptchaController.go

@@ -1,14 +1,10 @@
 package partial
 
 import (
-	"git.qianqiusoft.com/qianqiusoft/light-apiengine/entitys"
-	//sysmodel "git.qianqiusoft.com/qianqiusoft/light-apiengine/models"
-	//sysutils "git.qianqiusoft.com/qianqiusoft/light-apiengine/utils"
-	//"git.qianqiusoft.com/qianqiusoft/light-apiengine/models"
 	sysmodel "git.qianqiusoft.com/qianqiusoft/light-apiengine/models"
-	//__import_packages__
-	"github.com/dchest/captcha"
-	"bytes"
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/entitys"
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/utils"
+	"strconv"
 )
 
 const captcha_session = "image_captcha"
@@ -16,21 +12,28 @@ const captcha_session = "image_captcha"
 // _Image
 // @Title _Image
 // @Description 获取图片验证码
+// @Param	w	int  图片宽度
+// @Param	h	int  图片高度
+// @Param	code	string  保存的session编码
 // @Success 200 {object} Account
 // @Failure 403 :id is empty
 func Captcha_Image(c *entitys.CtrlContext) {
-	var content bytes.Buffer
-
-	captchaId := captcha.New()
+	width, _ := strconv.Atoi(c.Ctx.Query("w"))
+	height, _ := strconv.Atoi(c.Ctx.Query("h"))
+	length, _ := strconv.Atoi(c.Ctx.Query("l"))
+	captchaKey := captcha_session + c.Ctx.Query("code")
+	captchaId, image, err := utils.GenerateImageCaptcha(width, height, length)
 
-	c.Ctx.Set(captcha_session, captchaId)
-
-	err := captcha.WriteImage(&content, captchaId, 240, 80)
 	if err == nil {
+		utils.SetSession(c.Ctx, captchaKey, captchaId)
+		c.Ctx.Header("Cache-Control", "no-cache, no-store, must-revalidate")
+		c.Ctx.Header("Pragma", "no-cache")
+		c.Ctx.Header("Expires", "0")
 		c.Ctx.Header("Content-Type", "image/png")
-		c.Ctx.Writer.Write(content.Bytes())
+		c.Ctx.Writer.Write(image.Bytes())
 		c.Ctx.JSON(200, sysmodel.SysReturn{200, "", nil})
 	} else {
+		utils.SetSession(c.Ctx, captchaKey, "")
 		c.Ctx.JSON(500, sysmodel.SysReturn{500, err.Error(), nil})
 	}
 }
@@ -38,17 +41,67 @@ func Captcha_Image(c *entitys.CtrlContext) {
 // _Sms
 // @Title _Sms
 // @Description 获取短信验证码
-// @Param	phone    string  false  "手机号码"
+// @Param	mobile    string  false  "手机号码"
 // @Success 200 {object} Account
 // @Failure 403 :id is empty
 func Captcha_Sms(c *entitys.CtrlContext) {
-	phone := c.Ctx.Query("phone")
+	mobile := c.Ctx.Query("mobile")
 
-	ret := __none_func_captcha__(phone)
-	if ret {
-		c.Ctx.JSON(200, sysmodel.SysReturn{200, "", nil})
+	if mobile == "" {
+		c.Ctx.JSON(500, sysmodel.SysReturn{500, "mobile is cannot empty", nil})
+		return
+	}
+
+	data, err := utils.SendSmsCaptcha(mobile)
+	if err == nil {
+		c.Ctx.JSON(200, sysmodel.SysReturn{200, "", string(data)})
 	} else {
-		c.Ctx.JSON(500, sysmodel.SysReturn{500, "", nil})
+		c.Ctx.JSON(500, sysmodel.SysReturn{500, err.Error(), nil})
+	}
+}
+
+// _Check
+// @Title _Check
+// @Description 校验验证码
+// @Param	type    int  false  "验证类型 0:图片验证码 1:短信验证码"
+// @Param	captcha    string  false  "验证码"
+// @Param	mobile    string  false  "手机号码 短信验证码时传"
+// @Success 200 {object} Account
+// @Failure 403 :id is empty
+func Captcha_Check(c *entitys.CtrlContext) {
+	check_type := c.Ctx.Query("type")
+	captcha := c.Ctx.Query("captcha")
+	if captcha == "" {
+		c.Ctx.JSON(200, sysmodel.SysReturn{200, "验证码不能为空", nil})
+		return
+	}
+
+	var check = false //校验结果
+
+	switch check_type {
+	case "0":
+		captchaKey := captcha_session + c.Ctx.Query("code")
+		captchaId := utils.GetSession(c.Ctx, captchaKey, "").(string)
+		check = utils.ImageCaptchaCheck(captcha, captchaId)
+		if check {
+			c.Ctx.Set(captchaKey, "")
+		}
+	case "1":
+		mobile := c.Ctx.Query("mobile")
+		if mobile == "" {
+			c.Ctx.JSON(500, sysmodel.SysReturn{500, "手机号码不能为空", nil})
+			return
+		}
+		check= utils.SmsCaptchaCheck(captcha, mobile)
+	default:
+		c.Ctx.JSON(500, sysmodel.SysReturn{500, "验证类型错误", nil})
+		return
+	}
+
+	if check {
+		c.Ctx.JSON(200, sysmodel.SysReturn{200, "验证成功", nil})
+	}else{
+		c.Ctx.JSON(500, sysmodel.SysReturn{500, "验证失败", nil})
 	}
 }
 

+ 24 - 0
light-apiengine.xml

@@ -536,6 +536,30 @@
                 <param name="sys" desc="是否包含用户管理相关接口" type="string"></param>
             </api>
         </controller>
+        <controller name="captcha" desc="验证码" skip_login="true">
+            <api name="image" desc="获取图片验证码" method="get">
+                <return>
+                    <success ref="$sys_return"></success>
+                    <failure ref="$sys_return"></failure>
+                </return>
+            </api>
+            <api name="sms" desc="获取短信验证码" method="get">
+                <param name="mobile" type="string" desc="手机号码"></param>
+                <return>
+                    <success ref="$sys_return"></success>
+                    <failure ref="$sys_return"></failure>
+                </return>
+            </api>
+            <api name="check" desc="校验验证码" method="get">
+                <param name="type" type="int" desc="验证类型 0:图片验证码 1:短信验证码"></param>
+                <param name="captcha" type="string" desc="验证码"></param>
+                <param name="mobile" type="string" desc="手机号码 短信验证码时传"></param>
+                <return>
+                    <success ref="$sys_return"></success>
+                    <failure ref="$sys_return"></failure>
+                </return>
+            </api>
+        </controller>
     </controllers>
     <beans>
         <bean name="sys_org_tree" desc="组织架构" inher="$sys_org">

+ 158 - 0
utils/captcha_util.go

@@ -0,0 +1,158 @@
+package utils
+
+import (
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/config"
+	"git.qianqiusoft.com/qianqiusoft/light-apiengine/logs"
+
+	"github.com/dchest/captcha"
+	"errors"
+	"bytes"
+	"time"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	//"github.com/gin-contrib/sessions"
+)
+
+func init() {
+	imageCaptchaConfig.length = captcha.DefaultLen
+	imageCaptchaConfig.collect_num = captcha.CollectNum
+	imageCaptchaConfig.expiration = captcha.Expiration
+
+	sms_url := config.AppConfig.GetKey("sms_url")
+	sms_tmpl := config.AppConfig.GetKey("sms_tmpl")
+	smsConfig.send_format = fmt.Sprintf("%s/send?mobile=%%s&name=%s", sms_url, sms_tmpl)
+	smsConfig.check_format = fmt.Sprintf("%s/check?mobile=%%s&code=%%s", sms_url)
+}
+
+var imageCaptchaConfig struct {
+	// 验证码长度
+	length int
+	// 验证码缓存数量
+	collect_num int
+	// 验证码超时时间
+	expiration time.Duration
+}
+
+// @Description 生成图片验证码
+// @Params width int 生成图片的宽高
+// @Return id string 验证码id
+// @Return image *bytes.Buffer 图片buffer
+// @Return err error 错误
+func GenerateImageCaptcha(width, height, length int) (string, *bytes.Buffer, error) {
+	var captchaId string
+	var image bytes.Buffer
+	if width <= 0 {
+		width = 240
+	}
+	if height <= 0 {
+		height = 80
+	}
+	if length <= 0 {
+		length = imageCaptchaConfig.length
+	}
+	captchaId = captcha.NewLen(length)
+	err := captcha.WriteImage(&image, captchaId, width, height)
+	return captchaId, &image, err
+}
+
+// @Description 图片验证码校验
+// @Param code string 验证码
+// @Param id 验证码id 手机号码
+// @Return result bool 验证结果 true 成功 false 失败
+func ImageCaptchaCheck(code, id string) bool {
+	if code == "" || id == "" {
+		return false
+	}
+	return captcha.VerifyString(id, code)
+}
+
+// @Description 设置图片验证码长度
+// @Param length int 验证码长度
+func SetImageCaptchaLength(length int) {
+	if length != imageCaptchaConfig.length {
+		imageCaptchaConfig.length = length
+	}
+}
+
+// @Description 设置图片验证码超时时间
+// @Param expiration time.Duration 超时时间
+func SetImageCaptchaExpiration(expiration time.Duration) {
+	if expiration != imageCaptchaConfig.expiration {
+		imageCaptchaConfig.expiration = expiration
+		memoryStore := captcha.NewMemoryStore(imageCaptchaConfig.collect_num, expiration)
+		captcha.SetCustomStore(memoryStore)
+	}
+}
+
+// @Description 设置图片验证码缓存数量
+// @Param collect_num int 缓存数量
+func SetImageCaptchaCollectNum(collect_num int) {
+	if collect_num != imageCaptchaConfig.collect_num {
+		imageCaptchaConfig.collect_num = collect_num
+		memoryStore := captcha.NewMemoryStore(collect_num, imageCaptchaConfig.expiration)
+		captcha.SetCustomStore(memoryStore)
+	}
+}
+
+var smsConfig struct {
+	send_format string
+	check_format string
+}
+
+// @Description 发送短信验证码
+// @Param mobile string 手机号码
+// @Return data []byte 发送结果
+// @Return err error 错误
+func SendSmsCaptcha(mobile string) ([]byte, error) {
+	if mobile == "" {
+		return nil, errors.New("mobile is cannot empty")
+	}
+	sms_url := fmt.Sprintf(smsConfig.send_format, mobile)
+	logs.Debug("-----sms_send_url-------")
+	logs.Debug(sms_url)
+	data, err := NewHttpUtil().Get(sms_url, nil, nil)
+	logs.Debug(string(data))
+	if err != nil {
+		logs.Error("send sms captcha failure:", err)
+	}
+	return data, err
+}
+
+// @Description 短信验证码校验
+// @Param captcha string 验证码
+// @Param mobile string 手机号码
+// @Return result bool 验证结果 true 成功 false 失败
+func SmsCaptchaCheck(captcha, mobile string) bool {
+	if captcha == "" || mobile == "" {
+		return false
+	}
+	sms_url := fmt.Sprintf(smsConfig.check_format, mobile, captcha)
+	logs.Debug("-----sms_check_url-------")
+	logs.Debug(sms_url)
+	data, err := NewHttpUtil().Get(sms_url, nil, nil)
+	return err == nil && string(data) != "0"
+}
+
+// @Description 设置session
+// @Param ctx *gin.Context gin上下文
+// @Param key string 键
+// @Param value string 值
+func SetSession(ctx *gin.Context, key, value interface{}) {
+	/*session := sessions.Default(ctx)
+	session.Set(key, value)
+	session.Save()*/
+}
+
+// @Description 获取session
+// @Param ctx *gin.Context gin上下文
+// @Param key string 键
+// @Param value string 值
+func GetSession(ctx *gin.Context, key interface{}, defalutValue ...interface{}) interface{} {
+	return nil
+	/*session := sessions.Default(ctx)
+	value := session.Get(key)
+	if value == nil && len(defalutValue) > 0 {
+		return defalutValue[0]
+	}
+	return value*/
+}