作者 yangfu

yunpian sms

appname = ability
appname = 能力展示
httpport = 8080
runmode = dev
... ...
... ... @@ -5,4 +5,8 @@ data_source = "root:123456@tcp(127.0.0.1:3306)/ability_display"
#redis相关配置
redis_add_port = "127.0.0.1:6379"
redis_auth = "123456"
\ No newline at end of file
redis_auth = "123456"
#sms相关配置
yunpian_sms_sdk_url ="https://sms.yunpian.com/v2/sms/single_send.json"
yunpian_app_key ="0bf6fb10a11a68a95dee80901eb545b5"
\ No newline at end of file
... ...
... ... @@ -7,6 +7,8 @@ const (
LoginSmdcode ="signInCaptcha"
)
var Nums =[]byte("0123456789")
type RequestHeader struct {
TimeStamp string
Uuid string
... ... @@ -32,6 +34,9 @@ type LoginResponse struct {
/*SmsCode*/
type SmsCodeRequest struct {
Phone string `json:"phone" valid:"Required;Mobile"`
Content string `json:"-"`
SendType string `json:"send_type"`//sms_login_code sms_change_mobile
}
type SmsCodeResponse struct {
}
... ...
package protocol
//短信类型
const (
SmsLoginCode ="sms_login_code"
SmsChangeMobile="sms_change_mobile"
)
type SmsInfo struct {
Code string `json:"code"`
Count int `json:"count"`
ErrorCount int `json:"error_count"`
LastTime int64 `json:"last_time"`
CreateTime int64 `json:"create_time"`
}
\ No newline at end of file
... ...
package auth
import (
"bytes"
"fmt"
"github.com/astaxie/beego"
"gitlab.fjmaimaimai.com/mmm-go/ability/internal/repository"
"gitlab.fjmaimaimai.com/mmm-go/ability/models"
"gitlab.fjmaimaimai.com/mmm-go/ability/protocol"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/common"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/redis"
s_sms "gitlab.fjmaimaimai.com/mmm-go/ability/services/sms"
comm_time "gitlab.fjmaimaimai.com/mmm-go/gocomm/time"
"html/template"
"strings"
"encoding/json"
"time"
)
type IAuthService interface {
... ... @@ -28,7 +36,7 @@ func assertImplement(){
var(
//服务
//sms s_sms.ISmsService = &s_sms.SmsService{}
sms s_sms.ISmsService = &s_sms.YunPianSmsService{}
//仓储
UserRepository repository.IUserRepository =&repository.UserRepository{}
... ... @@ -39,6 +47,7 @@ func (s *AuthService)Login(request *protocol.LoginRequest)(rsp *protocol.LoginRe
var (
user *models.Users
userInfo *models.UserInfo
result bool
)
user,err =UserRepository.GetUsersByMobile(request.Phone)
if err!=nil{
... ... @@ -56,7 +65,11 @@ func (s *AuthService)Login(request *protocol.LoginRequest)(rsp *protocol.LoginRe
}
break
case protocol.LoginSmdcode:
goto Success
if result,err=CheckSmsCode(request);result && err==nil{
goto Success
}else{
return
}
default:
err =fmt.Errorf("grantType error")
return
... ... @@ -168,5 +181,103 @@ func (s *AuthService)CheckUuid(request *protocol.CheckUuidRequest)(rsp *protocol
}
//短信验证码
func (s *AuthService)SmsCode(request *protocol.SmsCodeRequest)(rsp *protocol.SmsCodeResponse,err error){
return nil,nil
var(
value,key,msgContent string
smsInfo *protocol.SmsInfo
)
msgContent = `【买买买信息科技】{{.Code}}({{.AppName}}手机验证码,请完成验证),如非本人操作,请忽略本短信`
switch request.SendType {
case protocol.SmsLoginCode:
case protocol.SmsChangeMobile:
default:
err = common.NewErrorWithMsg(2,"send_type error.")
return
}
key = request.SendType
//check user phone exists
if !redis.Hexists(key,request.Phone){
smsInfo = &protocol.SmsInfo{
CreateTime:time.Now().Unix(),
}
goto Send
}else{
if value,err =redis.Hget(key,request.Phone);err!=nil{
log.Error(err)
return
}
if err=json.Unmarshal([]byte(value),&smsInfo);err!=nil{
log.Error(err)
return
}
//第二天重置
if smsInfo.LastTime<comm_time.GetUnixTimeByYyyymmdd(){
smsInfo.Count=0
smsInfo.CreateTime = time.Now().Unix()
}
if smsInfo.Count>100{//TODO:limit send time
return
}
goto Send
}
Send:
{
smsInfo.Code = common.RandomStringWithChars(6,string(protocol.Nums))
smsInfo.LastTime=time.Now().Unix()
smsInfo.ErrorCount =0
//Todo Lock
smsInfo.Count +=1
if err=redis.Hset(key,request.Phone,common.AssertJson(smsInfo),-1);err!=nil{
return
}
tp :=template.New("sms_code")
tp.Parse(msgContent)
buf :=bytes.NewBuffer(nil)
tp.Execute(
buf,
map[string]string{
"Code":smsInfo.Code,
"AppName":beego.BConfig.AppName,
},)
request.Content = buf.String()
err = sms.Send(request)
}
return
}
//验证短信验证码
func CheckSmsCode(request *protocol.LoginRequest)(result bool,err error){
var(
value string
smsInfo *protocol.SmsInfo
)
result =false
if value,err =redis.Hget(protocol.SmsLoginCode,request.Phone);err!=nil{
err = common.NewErrorWithMsg(1009,"smscode expire")
return
}
if err=json.Unmarshal([]byte(value),&smsInfo);err!=nil{
return
}
if smsInfo.ErrorCount>=5{
err = common.NewErrorWithMsg(1011,"smscode over error times")
return
}
if smsInfo.LastTime+60*5<time.Now().Unix(){
err = common.NewErrorWithMsg(1009,"smscode expire")
goto Fail
}
if smsInfo.Code == request.Code{
result = true
return
}else{
err = common.NewErrorWithMsg(1012,"smscode error")
goto Fail
}
Fail:
{
smsInfo.ErrorCount +=1
if err=redis.Hset(protocol.SmsLoginCode,request.Phone,common.AssertJson(smsInfo),-1);err!=nil{
return
}
}
return
}
\ No newline at end of file
... ...
package sms
type ISmsService interface {
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/httplib"
"gitlab.fjmaimaimai.com/mmm-go/ability/protocol"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/common"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log"
)
type ISmsService interface {
Send(request *protocol.SmsCodeRequest)(err error)
}
type SmsService struct {}
type YunPianSmsService struct {}
func assertImplement(){
var _ ISmsService = (*SmsService)(nil)
var _ ISmsService = (*YunPianSmsService)(nil)
}
//发送
func(s *YunPianSmsService)Send(request *protocol.SmsCodeRequest)(err error){
var (
resp *YunPianResponse
)
log.Debug("[sms] mobile:",request.Phone," content:",request.Content)
if beego.BConfig.RunMode!="prod"{
return
}
post:= httplib.Post(beego.AppConfig.String("yunpian_sms_sdk_url"))
post.Param("apikey",beego.AppConfig.String("yunpian_app_key"))
post.Param("mobile",request.Phone)
post.Param("text",request.Content)
if err= post.ToJSON(&resp);err!=nil{
return
}
if resp.Code!=0 || resp.Mobile!=request.Phone{
log.Error("yunpian send sms code:",resp.Code," error msg:",resp.Msg)
err = common.NewErrorWithMsg(1,resp.Msg)
}
return nil
}
type YunPianResponse struct {
Code int `json:"code"` //0代表发送成功,其他code代表出错,详细见"返回值说明"页面
Msg string `json:"msg"`//例如""发送成功"",或者相应错误信息
Count int `json:"count"`//发送成功短信的计费条数(计费条数:70个字一条,超出70个字时按每67字一条计费)
Mobile string `json:"string"`//发送手机号
Fee float64 `json:"fee"` //扣费金额,单位:元,类型:双精度浮点型/double
Sid int64 `json:"sid"` //短信id,64位整型
}
\ No newline at end of file
... ...