Files
jx-callback/business/jxcallback/auth/weixin/weixin.go
2018-12-28 10:04:38 +08:00

222 lines
6.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}