1
This commit is contained in:
61
services/print_server/app_server/verify_code.go
Normal file
61
services/print_server/app_server/verify_code.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package app_server
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-print/globals"
|
||||
"git.rosy.net.cn/jx-print/putils"
|
||||
"git.rosy.net.cn/jx-print/services/api"
|
||||
aliyunsmsclient "github.com/KenmyZhang/aliyun-communicate"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
type SendVerifyCode struct {
|
||||
}
|
||||
|
||||
var SendVerifyCodeServer = new(SendVerifyCode)
|
||||
|
||||
// SendCode 获取手机短信验证码
|
||||
func (s *SendVerifyCode) SendCode(mobile string) (string, error) {
|
||||
// 获取code
|
||||
smsCode := ""
|
||||
code := putils.GetKey(mobile)
|
||||
if code != "" {
|
||||
smsCode = code.(string)
|
||||
} else {
|
||||
smsCode = fmt.Sprintf("%06d", rand.Intn(1000000))
|
||||
}
|
||||
|
||||
// 发送短信
|
||||
response, err := api.SMSClient.Execute(globals.AliKey, globals.AliSecret, mobile, globals.SmsSignName, globals.SmsMobileVerifyTemplate, string(utils.MustMarshal(map[string]interface{}{
|
||||
"code": smsCode,
|
||||
})))
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if response.Code != aliyunsmsclient.ResponseCodeOk {
|
||||
return "", fmt.Errorf("发送短信出错:%s", response.Message)
|
||||
}
|
||||
|
||||
if err := putils.SetKey(response.BizId+"_"+mobile, smsCode, 5*60); err != nil {
|
||||
globals.SugarLogger.Debugf("redis set key err key[%s] value[%s]:", mobile, smsCode)
|
||||
return "", err
|
||||
}
|
||||
|
||||
return response.BizId, nil
|
||||
}
|
||||
|
||||
// VerifySecret 检查验证码
|
||||
func (s *SendVerifyCode) VerifySecret(mobile, bizId, code string) (bool, error) {
|
||||
result := putils.GetKey(bizId + "_" + mobile)
|
||||
if result != "" {
|
||||
return false, errors.New("验证码过期")
|
||||
}
|
||||
if result.(string) != code {
|
||||
return false, errors.New("验证码错误,重新确认")
|
||||
}
|
||||
putils.DelKey(bizId + "_" + mobile)
|
||||
return true, nil
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
package app_server
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -17,7 +14,6 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -27,14 +23,14 @@ type UserLogin struct {
|
||||
}
|
||||
|
||||
// WxLogin 授权登录
|
||||
func (u *UserLogin) WxLogin(ctx *gin.Context, param *wxLogin.WeChatPhoneNumberParam) (*model.User, error) {
|
||||
func (u *UserLogin) WxLogin(ctx *gin.Context, param *wxLogin.WxLoginReq) (*model.User, error) {
|
||||
openObj, err := api.WeixinMiniAPI.SNSCode2Session(param.Code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 检查用户是否存在
|
||||
users, err := dao.GetUsers(globals.GetDB(), "", "", "", openObj.OpenID)
|
||||
users, err := dao.GetUsers(globals.GetDB(), "", "", param.Phone, openObj.OpenID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -42,11 +38,6 @@ func (u *UserLogin) WxLogin(ctx *gin.Context, param *wxLogin.WeChatPhoneNumberPa
|
||||
return nil, errors.New("数据异常,用户电话不唯一,联系管理员")
|
||||
}
|
||||
|
||||
weChatLogin := new(wxLogin.UserPhone)
|
||||
if err := DecryptOpenDataToStruct(param.EncryptedData, param.IV, openObj.SessionKey, weChatLogin); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var userObj *model.User
|
||||
timeNow := time.Now()
|
||||
switch len(users) {
|
||||
@@ -60,7 +51,7 @@ func (u *UserLogin) WxLogin(ctx *gin.Context, param *wxLogin.WeChatPhoneNumberPa
|
||||
UserID: utils.GetUUID(),
|
||||
Password: "",
|
||||
Name: param.NickName,
|
||||
Mobile: weChatLogin.PhoneNumber,
|
||||
Mobile: param.Phone,
|
||||
Email: "",
|
||||
Avatar: param.HeadUrl,
|
||||
Status: 1,
|
||||
@@ -88,79 +79,106 @@ func (u *UserLogin) WxLogin(ctx *gin.Context, param *wxLogin.WeChatPhoneNumberPa
|
||||
users[0].Avatar = param.HeadUrl
|
||||
users[0].OpenId = openObj.OpenID
|
||||
users[0].UnionId = openObj.UnionID
|
||||
// 用户存在,判断用户
|
||||
users[0].UpdatedAt = &timeNow
|
||||
users[0].LastOperator = users[0].Name
|
||||
users[0].LastLoginIP = ctx.ClientIP()
|
||||
if err := dao.UpdateUserWx(users[0], []string{"updated_at", "last_operator", "last_login_ip", "name", "avatar", "open_id", "union_id"}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
// 用户存在,判断用户
|
||||
users[0].UpdatedAt = &timeNow
|
||||
users[0].LastOperator = users[0].Name
|
||||
users[0].LastLoginIP = ctx.ClientIP()
|
||||
if err := dao.UpdateUserWx(users[0], []string{"updated_at", "last_operator", "last_login_ip"}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// 用户存在,判断用户
|
||||
users[0].UpdatedAt = &timeNow
|
||||
users[0].LastOperator = users[0].Name
|
||||
users[0].LastLoginIP = ctx.ClientIP()
|
||||
if err := dao.UpdateUserWx(users[0], []string{"updated_at", "last_operator", "last_login_ip", "name", "avatar", "open_id", "union_id"}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userObj = users[0]
|
||||
}
|
||||
|
||||
return userObj, err
|
||||
}
|
||||
|
||||
// DecryptOpenDataToStruct 解密开放数据到结构体
|
||||
// encryptedData:包括敏感数据在内的完整用户信息的加密数据,小程序获取到
|
||||
// iv:加密算法的初始向量,小程序获取到
|
||||
// sessionKey:会话密钥,通过 gopay.Code2Session() 方法获取到
|
||||
// beanPtr:需要解析到的结构体指针,操作完后,声明的结构体会被赋值
|
||||
// 文档:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html
|
||||
func DecryptOpenDataToStruct(encryptedData, iv, sessionKey string, beanPtr interface{}) (err error) {
|
||||
if encryptedData == "" || iv == "" || sessionKey == "" {
|
||||
return errors.New("input params can not null")
|
||||
// MobileLogin 短信验证登录
|
||||
func (u *UserLogin) MobileLogin(ctx *gin.Context, param *wxLogin.MobileLogin) (*model.User, error) {
|
||||
// 校验用户信息
|
||||
isHave, err := SendVerifyCodeServer.VerifySecret(param.Phone, param.BizId, param.Code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var (
|
||||
cipherText, aesKey, ivKey, plainText []byte
|
||||
block cipher.Block
|
||||
blockMode cipher.BlockMode
|
||||
)
|
||||
beanValue := reflect.ValueOf(beanPtr)
|
||||
if beanValue.Kind() != reflect.Ptr {
|
||||
return errors.New("传入beanPtr类型必须是以指针形式")
|
||||
if !isHave {
|
||||
return nil, errors.New("验证码错误")
|
||||
}
|
||||
if beanValue.Elem().Kind() != reflect.Struct {
|
||||
return errors.New("传入interface{}必须是结构体")
|
||||
// 检查用户是否存在
|
||||
users, err := dao.GetUsers(globals.GetDB(), "", "", param.Phone, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cipherText, _ = base64.StdEncoding.DecodeString(encryptedData)
|
||||
aesKey, _ = base64.StdEncoding.DecodeString(sessionKey)
|
||||
ivKey, _ = base64.StdEncoding.DecodeString(iv)
|
||||
if len(cipherText)%len(aesKey) != 0 {
|
||||
return errors.New("encryptedData is error")
|
||||
}
|
||||
if block, err = aes.NewCipher(aesKey); err != nil {
|
||||
return fmt.Errorf("aes.NewCipher:%w", err)
|
||||
}
|
||||
blockMode = cipher.NewCBCDecrypter(block, ivKey)
|
||||
plainText = make([]byte, len(cipherText))
|
||||
blockMode.CryptBlocks(plainText, cipherText)
|
||||
if len(plainText) > 0 {
|
||||
plainText = PKCS7UnPadding(plainText)
|
||||
}
|
||||
if err = json.Unmarshal(plainText, beanPtr); err != nil {
|
||||
return fmt.Errorf("json.Marshal(%s):%w", string(plainText), err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// PKCS7UnPadding 解密填充模式(去除补全码) PKCS7UnPadding
|
||||
// 解密时,需要在最后面去掉加密时添加的填充byte
|
||||
func PKCS7UnPadding(origData []byte) (bs []byte) {
|
||||
length := len(origData)
|
||||
unPaddingNumber := int(origData[length-1]) // 找到Byte数组最后的填充byte 数字
|
||||
if unPaddingNumber <= 16 {
|
||||
bs = origData[:(length - unPaddingNumber)] // 只截取返回有效数字内的byte数组
|
||||
} else {
|
||||
bs = origData
|
||||
var userObj *model.User
|
||||
timeNow := time.Now()
|
||||
switch len(users) {
|
||||
case 1: // 用户存在
|
||||
userObj = users[0]
|
||||
case 0: // 用户不存在
|
||||
// 用户不存在,创建并返回用户
|
||||
userBase := &model.User{
|
||||
CreatedAt: &timeNow,
|
||||
UpdatedAt: &timeNow,
|
||||
LastOperator: "系统新增",
|
||||
DeletedAt: &utils.DefaultTimeValue,
|
||||
UserID: utils.GetUUID(),
|
||||
Password: "",
|
||||
Name: "手机用户_" + param.Phone,
|
||||
Mobile: param.Phone,
|
||||
Email: "",
|
||||
Avatar: "",
|
||||
Status: 1,
|
||||
Type: 1,
|
||||
Company: "",
|
||||
CityCode: 0,
|
||||
DistrictCode: 0,
|
||||
Address: "",
|
||||
IDCardNo: "",
|
||||
Remark: "",
|
||||
LastLoginAt: &timeNow,
|
||||
LastLoginIP: ctx.ClientIP(),
|
||||
LastLoginType: model.OrderOriginMobile,
|
||||
OpenId: "",
|
||||
UnionId: "",
|
||||
}
|
||||
if err := dao.CreateUserWx(userBase); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userObj = userBase
|
||||
}
|
||||
return
|
||||
return userObj, nil
|
||||
}
|
||||
|
||||
// GetUserPhoneNum 解密用户手机号
|
||||
func (u *UserLogin) GetUserPhoneNum(param *wxLogin.WeChatPhoneNumberParam) (string, error) {
|
||||
return api.WeixinMiniAPI.SNSGetUserPhone(param.Code)
|
||||
func (u *UserLogin) GetUserPhoneNum(param *wxLogin.WeChatPhoneNumberParam) (string, bool, error) {
|
||||
phone, err := api.WeixinMiniAPI.SNSGetUserPhone(param.Code)
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
// 检查用户是否存在
|
||||
users, err := dao.GetUsers(globals.GetDB(), "", "", phone, "")
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
if len(users) != 1 {
|
||||
return phone, false, nil
|
||||
}
|
||||
|
||||
isRegion := false
|
||||
if users[0].OpenId != "" {
|
||||
isRegion = true
|
||||
}
|
||||
|
||||
return phone, isRegion, nil
|
||||
}
|
||||
|
||||
// Jxc4UserToken 全局变量,缓存菜市管理系统token
|
||||
|
||||
@@ -10,6 +10,35 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// QueryPrintKeyIsExit 查询用户打印机以及绑定信息
|
||||
func QueryPrintKeyIsExit(printInfo *model.PrintInfo, phone, bizId, code string, appId int) error {
|
||||
var (
|
||||
db = globals.GetDB()
|
||||
)
|
||||
// 电话号码校验
|
||||
have, err := SendVerifyCodeServer.VerifySecret(phone, bizId, code)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !have {
|
||||
return fmt.Errorf("验证码错误")
|
||||
}
|
||||
|
||||
if printInfo.PrintNo == "" {
|
||||
return fmt.Errorf("请输入正确的打印机编号!print_no :%s 。", printInfo.PrintNo)
|
||||
}
|
||||
|
||||
printers, _ := dao.GetPrinters(db, appId, printInfo.PrintNo, 0, 0, 0)
|
||||
// 打印机已经被绑定
|
||||
if len(printers) != 0 {
|
||||
// 修改绑定
|
||||
if printers[0].PrintKey != "" && printers[0].PrintKey != phone {
|
||||
return fmt.Errorf("打印机已经被其他用户绑定,修改绑定请联系商家")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func AddPrinters(tokenInfo *model.TokenInfo, appID int, printInfo []*model.PrintInfo) (err error) {
|
||||
var (
|
||||
db = globals.GetDB()
|
||||
|
||||
Reference in New Issue
Block a user