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.WeixinMiniAPI.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.WeixinMiniAPI.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.WeixinMiniAPI.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 }