222 lines
6.3 KiB
Go
222 lines
6.3 KiB
Go
package weixin
|
||
|
||
import (
|
||
"encoding/base64"
|
||
"errors"
|
||
"fmt"
|
||
"time"
|
||
|
||
"git.rosy.net.cn/baseapi/platformapi/weixinapi"
|
||
"git.rosy.net.cn/baseapi/utils"
|
||
"git.rosy.net.cn/jx-callback/business/jxcallback/auth"
|
||
"git.rosy.net.cn/jx-callback/business/jxcallback/auth/mobile"
|
||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||
"git.rosy.net.cn/jx-callback/business/model/legacymodel"
|
||
"git.rosy.net.cn/jx-callback/globals"
|
||
"git.rosy.net.cn/jx-callback/globals/api"
|
||
"github.com/astaxie/beego/orm"
|
||
)
|
||
|
||
const (
|
||
LoginType = "weixinsns"
|
||
LoginTypeMiniProgram = "weixinmini"
|
||
DefTempPasswordDuration = 5 * time.Minute // 登录时间限制在5分钟内
|
||
)
|
||
|
||
const (
|
||
CacheKeySeparator = "/"
|
||
MiniVerifyCodePrefix = "MiniVerifyCode"
|
||
SessionKeyPrefix = "SessionKey"
|
||
)
|
||
|
||
var (
|
||
ErrLoginFailed = errors.New("登录失败")
|
||
StrStateIsWrong = "state:%s状态不对"
|
||
)
|
||
|
||
var (
|
||
auther *Auther
|
||
AutherMini *AutherMiniProgram
|
||
)
|
||
|
||
type Auther struct {
|
||
}
|
||
|
||
type AutherMiniProgram struct {
|
||
}
|
||
|
||
type UserInfoExt struct {
|
||
weixinapi.SNSUserInfo
|
||
TempPassword string `json:"tempPassword"` // 一段时间有效的登录密码
|
||
}
|
||
|
||
func init() {
|
||
auther = new(Auther)
|
||
auth.RegisterAuther(LoginType, auther)
|
||
|
||
AutherMini = new(AutherMiniProgram)
|
||
auth.RegisterAuther(LoginTypeMiniProgram, AutherMini)
|
||
}
|
||
|
||
func GetUserInfo(code string, state string) (token *UserInfoExt, err error) {
|
||
globals.SugarLogger.Debugf("GetUserInfo code:%s", code)
|
||
|
||
if state == "" {
|
||
token, err2 := api.WeixinAPI.SNSGetToken(code)
|
||
if err = err2; err == nil {
|
||
wxUserinfo, err2 := api.WeixinAPI.SNSGetUserInfo(token.AccessToken, token.OpenID)
|
||
if err = err2; err == nil {
|
||
pwd := utils.GetUUID()
|
||
globals.SugarLogger.Debugf("GetUserInfo code:%s, pwd:%s", code, pwd)
|
||
api.Cacher.Set(wxUserinfo.OpenID, pwd, DefTempPasswordDuration)
|
||
return &UserInfoExt{
|
||
SNSUserInfo: *wxUserinfo,
|
||
TempPassword: pwd,
|
||
}, nil
|
||
}
|
||
}
|
||
} else {
|
||
err = fmt.Errorf(StrStateIsWrong, state)
|
||
}
|
||
return nil, err
|
||
}
|
||
|
||
func (a *Auther) Login(openid, password string) (userID string, err error) {
|
||
globals.SugarLogger.Debugf("weixinsns Login openid:%s, password:%s", openid, password)
|
||
|
||
if value := api.Cacher.Get(openid); value != nil {
|
||
if password == value.(string) {
|
||
// wxUser := &legacymodel.WeiXins{
|
||
// OpenID: openid,
|
||
// }
|
||
// if err = dao.GetEntity(nil, wxUser, "OpenID"); err == nil {
|
||
api.Cacher.Del(openid)
|
||
return "", nil
|
||
// }
|
||
}
|
||
} else {
|
||
err = ErrLoginFailed
|
||
}
|
||
return "", err
|
||
}
|
||
|
||
func (a *Auther) Logout(loginInfo *auth.LoginInfo) error {
|
||
return nil
|
||
}
|
||
|
||
func BindMobile(token, mobileNum, code, nickname string) (err error) {
|
||
globals.SugarLogger.Debugf("BindMobile mobileNum:%s, code:%s, nickname:%s", mobileNum, code, nickname)
|
||
|
||
loginInfo := new(auth.LoginInfo)
|
||
if err = api.Cacher.GetAs(token, loginInfo); err == nil {
|
||
if mobile.VerifyCode(mobileNum, code) {
|
||
user := &legacymodel.WeiXins{
|
||
OpenID: loginInfo.ID,
|
||
Tel: mobileNum,
|
||
NickName: nickname,
|
||
ParentID: -1,
|
||
}
|
||
db := dao.GetDB()
|
||
if err = dao.GetEntity(db, user, "OpenID"); err == nil {
|
||
user.Tel = mobileNum
|
||
user.NickName = nickname
|
||
_, err = dao.UpdateEntity(db, user, "Tel", "NickName")
|
||
} else if err == orm.ErrNoRows {
|
||
if err = dao.GetEntity(db, user, "Tel"); err == nil {
|
||
user.OpenID = loginInfo.ID
|
||
user.NickName = nickname
|
||
_, err = dao.UpdateEntity(db, user, "OpenID", "NickName")
|
||
}
|
||
}
|
||
if err == orm.ErrNoRows {
|
||
err = dao.CreateEntity(db, user)
|
||
}
|
||
} else {
|
||
err = errors.New("验证码错")
|
||
}
|
||
}
|
||
return err
|
||
}
|
||
|
||
// 对于小程序来说,
|
||
// 1,用户必须先在后台创建(手机号标识)
|
||
// 2,用户必须先绑定微信
|
||
// 先以短信方式登录:
|
||
// SendMobileVerifyCode
|
||
// Login use type mobile
|
||
// MiniBindWeiXin
|
||
// 3,用户以CODE来登录(Login use type weixinmini)
|
||
// Login
|
||
|
||
func (a *AutherMiniProgram) BindWeiXin(ctx *jxcontext.Context, code, nickName string) (err error) {
|
||
globals.SugarLogger.Debugf("AutherMiniProgram BindWeiXin code:%s, nickName:%s", code, nickName)
|
||
loginInfo := ctx.GetLoginInfo()
|
||
if loginInfo == nil || loginInfo.LoginType != mobile.LoginType {
|
||
return fmt.Errorf("调用AutherMiniProgram BindWeiXin时,必须以手机验证方式登录")
|
||
}
|
||
user := &legacymodel.WeiXins{
|
||
Tel: loginInfo.ID,
|
||
}
|
||
db := dao.GetDB()
|
||
if err = dao.GetEntity(db, user, "Tel"); err != nil {
|
||
return auth.ConvertErr2NoUser(err, loginInfo.ID)
|
||
}
|
||
sessionInfo, err := api.WeixinAPI.SNSCode2Session(code)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
user.OpenIDMini = sessionInfo.OpenID
|
||
if nickName != "" {
|
||
user.NickName = nickName
|
||
}
|
||
_, err = dao.UpdateEntity(db, user)
|
||
return err
|
||
}
|
||
|
||
func (a *AutherMiniProgram) Login(mobileNum, code string) (userID string, err error) {
|
||
globals.SugarLogger.Debugf("AutherMiniProgram Login mobileNum:%s, code:%s", mobileNum, code)
|
||
sessionInfo, err := api.WeixinAPI.SNSCode2Session(code)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
user := &legacymodel.WeiXins{
|
||
OpenIDMini: sessionInfo.OpenID,
|
||
}
|
||
db := dao.GetDB()
|
||
if err = dao.GetEntity(db, user, "OpenIDMini"); err != nil {
|
||
return "", auth.ConvertErr2NoUser(err, mobileNum)
|
||
}
|
||
if mobileNum != user.Tel {
|
||
|
||
}
|
||
api.Cacher.Set(composeSessionKeyCacheKey(sessionInfo.OpenID), sessionInfo.SessionKey, auth.DefTokenDuration)
|
||
return sessionInfo.OpenID, err
|
||
}
|
||
|
||
func (a *AutherMiniProgram) Logout(loginInfo *auth.LoginInfo) error {
|
||
globals.SugarLogger.Debugf("AutherMiniProgram Logout openid:%s", utils.Format4Output(loginInfo, false))
|
||
return api.Cacher.Del(composeSessionKeyCacheKey(loginInfo.ID))
|
||
}
|
||
|
||
func (a *AutherMiniProgram) DecryptData(ctx *jxcontext.Context, encryptedData, iv string) (decryptedDataBase64 string, err error) {
|
||
globals.SugarLogger.Debugf("AutherMiniProgram DecryptData encryptedData:%s, iv:%s", encryptedData, iv)
|
||
var sessionKey string
|
||
if err = api.Cacher.GetAs(composeSessionKeyCacheKey(ctx.GetLoginInfo().ID), &sessionKey); err != nil {
|
||
return "", err
|
||
}
|
||
decryptedData, err := api.WeixinAPI.SNSDecodeMiniProgramData(encryptedData, sessionKey, iv)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
return base64.StdEncoding.EncodeToString(decryptedData), nil
|
||
}
|
||
|
||
func composeMiniVerifiyCacheKey(key string) string {
|
||
return MiniVerifyCodePrefix + CacheKeySeparator + key
|
||
}
|
||
|
||
func composeSessionKeyCacheKey(key string) string {
|
||
return SessionKeyPrefix + CacheKeySeparator + key
|
||
}
|