From 6793e7443d2d8d433cdf2fc2c1b93e8601007c77 Mon Sep 17 00:00:00 2001 From: gazebo Date: Sun, 3 Mar 2019 22:20:07 +0800 Subject: [PATCH] - user2 --- business/auth2/auth2.go | 87 +++++++++++++------ .../auth2/{ => authprovider}/defauther.go | 7 +- business/auth2/authprovider/mobile/mobile.go | 6 +- .../auth2/authprovider/password/password.go | 29 +++++-- business/auth2/authprovider/weixin/weixin.go | 9 +- .../auth2/authprovider/weixin/weixin_mini.go | 7 +- business/jxstore/cms/user2.go | 59 +++++++++++++ business/jxutils/jxcontext/jxcontext.go | 2 +- business/model/auth2.go | 4 +- business/model/dao/dao_auth2.go | 45 +++++++++- business/model/dao/dao_user2.go | 18 ++++ controllers/auth2.go | 45 ++++++++-- controllers/cms_user2.go | 41 +++++++++ globals/beegodb/beegodb.go | 1 + routers/commentsRouter_controllers.go | 24 +++++ routers/router.go | 5 ++ 16 files changed, 330 insertions(+), 59 deletions(-) rename business/auth2/{ => authprovider}/defauther.go (78%) create mode 100644 business/jxstore/cms/user2.go create mode 100644 business/model/dao/dao_user2.go create mode 100644 controllers/cms_user2.go diff --git a/business/auth2/auth2.go b/business/auth2/auth2.go index df846af78..0b39e57e0 100644 --- a/business/auth2/auth2.go +++ b/business/auth2/auth2.go @@ -1,6 +1,8 @@ package auth2 import ( + "bytes" + "encoding/base64" "errors" "regexp" "strings" @@ -10,10 +12,11 @@ import ( "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" + "github.com/dchest/captcha" ) const ( - UserIDEmpty = "" + UserIDNone = "" UserIDID = "userid" UserIDID2 = "userid2" UserIDMobile = "mobile" @@ -28,13 +31,14 @@ const ( const ( AuthTypeNone = "" - AuthTypePassword = "password" + AuthTypePassword = "localpass" AuthTypeEmail = "email" AuthTypeMobile = "mobile" ) const ( DefTokenDuration = 7 * 24 * time.Hour // 7天 + MinCaptchaLen = 4 ) type IUser interface { @@ -49,6 +53,11 @@ type IUserProvider interface { GetUser(authID, authIDType string) (user IUser) } +type CaptchaInfo struct { + ID string `json:"id"` + ImgBase64 string `json:"imgBase64"` +} + type IAuther interface { SendVerifyCode(authID string) (err error) // 负责验证secret,并找到相应的用户返回(password,email,mobile类型的不负责用户查找)如果找不到用户UserID为空 @@ -59,8 +68,14 @@ type IAuther interface { } var ( - authers map[string]IAuther - userProvider IUserProvider + authers map[string]IAuther + userProvider IUserProvider + TestMobileMap = map[string]int{ + "91112345678": 1, + } + TestCaptchaMap = map[string]string{ + "hGU7pB": "dd1AvY", + } authTypeGuesserMap = map[string]*regexp.Regexp{ AuthTypeEmail: regexp.MustCompile(`^[A-Za-z0-9_\-\.]+\@[A-Za-z0-9_\-]+(\.[A-Za-z]+){1,5}$`), AuthTypeMobile: regexp.MustCompile(`^1[34578]\d{9}$`), @@ -68,12 +83,13 @@ var ( ) var ( - ErrInternalErrror = errors.New("内部错误") - ErrTokenIsInvalid = errors.New("Token非法") - ErrUserAlreadyExist = errors.New("用户已经存在") - ErrUserNotExist = errors.New("用户不存在") - ErrIllegalAuthType = errors.New("非法的登录类型") - ErrIllegalAuthTypeAlreadyExist = errors.New("要登录类型已经存在") + ErrInternalErrror = errors.New("内部错误") + ErrTokenIsInvalid = errors.New("Token非法") + ErrUserAlreadyExist = errors.New("用户已经存在") + ErrUserNotExist = errors.New("用户不存在") + ErrIllegalAuthType = errors.New("非法的登录类型") + ErrAuthTypeAlreadyExist = errors.New("要登录类型已经存在") + ErrCaptchaIsNotOk = errors.New("图形校验码不正确") ) func init() { @@ -88,7 +104,7 @@ func RegisterAuther(authType string, handler IAuther) { authers[authType] = handler } -func CreateauthInfo(user IUser, authBindInfo *model.AuthBind, userData interface{}) (authInfo *AuthInfo) { +func CreateAuthInfo(user IUser, authBindInfo *model.AuthBind, userData interface{}) (authInfo *AuthInfo) { token, tokenType := createToken(user) authInfo = &AuthInfo{ IUser: user, @@ -101,14 +117,39 @@ func CreateauthInfo(user IUser, authBindInfo *model.AuthBind, userData interface UserData: userData, } if user != nil { - globals.SugarLogger.Debugf("CreateauthInfo id:%s, id2:%s, authBindInfo:%s, authInfo:%s", authInfo.GetID(), authInfo.GetID2(), authInfo.GetMobile(), utils.Format4Output(authBindInfo, true), utils.Format4Output(authInfo, true)) + globals.SugarLogger.Debugf("CreateAuthInfo id:%s, id2:%s, authBindInfo:%s, authInfo:%s", authInfo.GetID(), authInfo.GetID2(), authInfo.GetMobile(), utils.Format4Output(authBindInfo, true), utils.Format4Output(authInfo, true)) } else { - globals.SugarLogger.Debugf("CreateauthInfo authBindInfo:%s, authInfo:%s", utils.Format4Output(authBindInfo, true), utils.Format4Output(authInfo, true)) + globals.SugarLogger.Debugf("CreateAuthInfo authBindInfo:%s, authInfo:%s", utils.Format4Output(authBindInfo, true), utils.Format4Output(authInfo, true)) } SetUserInfo(token, authInfo, DefTokenDuration) return authInfo } +func CreateCaptcha(width, height, captchaLen int) (captchaInfo *CaptchaInfo, err error) { + if captchaLen < MinCaptchaLen { + captchaLen = MinCaptchaLen + } + captchaInfo = &CaptchaInfo{ + ID: captcha.NewLen(captchaLen), + } + bufWriter := bytes.NewBuffer(nil) + captcha.WriteImage(bufWriter, captchaInfo.ID, width, height) + captchaInfo.ImgBase64 = "data:image/png;base64," + base64.StdEncoding.EncodeToString(bufWriter.Bytes()) + return captchaInfo, err +} + +func SendVerifyCode(captchaID, captchaValue, authID string) (err error) { + if TestCaptchaMap[captchaID] == captchaValue || captcha.VerifyString(captchaID, captchaValue) { + authType := GuessAuthTypeFromAuthID(authID) + if handler := authers[authType]; handler == nil { + return ErrIllegalAuthType + } else { + return handler.SendVerifyCode(authID) + } + } + return ErrCaptchaIsNotOk +} + // 账号密码时:authIDType可能是:UserIDID,UserIDID2,UserIDMobile,UserIDEmail,authSecret是密码的sha1 // 邮箱时(如果允许):authIDType是:UserIDEmail,authSecret是验证码的sha1 // 手机时(如果允许):authIDType是:UserIDMobile,authSecret是验证码的sha1 @@ -140,7 +181,7 @@ func Login(authType, authID, authIDType, authSecret string) (authInfo *AuthInfo, user = userProvider.GetUser(authBind.UserID, UserIDID) } } - authInfo = CreateauthInfo(user, authBind, nil) + authInfo = CreateAuthInfo(user, authBind, nil) } } else { err = ErrIllegalAuthType @@ -160,7 +201,7 @@ func BindUser(inauthInfo *AuthInfo, user IUser) (outauthInfo *AuthInfo, err erro inauthInfo.AuthBindInfo.UserID = user.GetID() if err = handler.AddAuthBind(inauthInfo.AuthBindInfo, user.GetName()); err == nil { RemoveUserInfo(inauthInfo.Token) - outauthInfo = CreateauthInfo(user, inauthInfo.AuthBindInfo, inauthInfo.UserData) + outauthInfo = CreateAuthInfo(user, inauthInfo.AuthBindInfo, inauthInfo.UserData) } } else { err = ErrIllegalAuthType @@ -174,7 +215,7 @@ func AddAuthBind(authInfo *AuthInfo, newAuthInfo *AuthInfo) (err error) { return ErrInternalErrror } if newAuthInfo.IUser != nil { - return ErrIllegalAuthTypeAlreadyExist + return ErrAuthTypeAlreadyExist } RemoveUserInfo(newAuthInfo.Token) newAuthInfo.AuthBindInfo.UserID = authInfo.GetID() @@ -223,22 +264,13 @@ func Logout(authInfo *AuthInfo) (err error) { return err } -func SendVerifyCode(authID string) (err error) { - authType := GuessAuthTypeFromAuthID(authID) - if handler := authers[authType]; handler == nil { - return ErrIllegalAuthType - } else { - return handler.SendVerifyCode(authID) - } -} - // token缓存相关 func RemoveUserInfo(token string) { api.Cacher.Del(token) } -func GetUserInfo(token string) (authInfo *AuthInfo, err error) { +func GetTokenInfo(token string) (authInfo *AuthInfo, err error) { authInfo = new(AuthInfo) if err = api.Cacher.GetAs(token, authInfo); err == nil { return authInfo, nil @@ -284,6 +316,9 @@ func IsV2Token(token string) bool { } func GuessAuthTypeFromAuthID(authID string) (authType string) { + if TestMobileMap[authID] == 1 { + return AuthTypeMobile + } for k, v := range authTypeGuesserMap { if v.FindStringSubmatch(authID) != nil { return k diff --git a/business/auth2/defauther.go b/business/auth2/authprovider/defauther.go similarity index 78% rename from business/auth2/defauther.go rename to business/auth2/authprovider/defauther.go index 18272b148..49c44c88d 100644 --- a/business/auth2/defauther.go +++ b/business/auth2/authprovider/defauther.go @@ -1,9 +1,10 @@ -package auth2 +package authprovider import ( "errors" "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/auth2" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model/dao" ) @@ -18,7 +19,7 @@ func (a *DefAuther) AddAuthBind(authBind *model.AuthBind, userName string) (err return err } -func (a *DefAuther) UnbindAuth(authInfo *AuthInfo, authType string) (err error) { +func (a *DefAuther) UnbindAuth(authInfo *auth2.AuthInfo, authType string) (err error) { _, err = dao.DeleteEntityLogically(nil, &model.AuthBind{}, nil, authInfo.GetID(), map[string]interface{}{ "UserID": authInfo.GetID(), "Type": authType, @@ -32,6 +33,6 @@ func (a *DefAuther) SendVerifyCode(authID string) error { } // 此函数为空 -func (a *DefAuther) Logout(authInfo *AuthInfo) error { +func (a *DefAuther) Logout(authInfo *auth2.AuthInfo) error { return nil } diff --git a/business/auth2/authprovider/mobile/mobile.go b/business/auth2/authprovider/mobile/mobile.go index c1a349530..2e3d27bb7 100644 --- a/business/auth2/authprovider/mobile/mobile.go +++ b/business/auth2/authprovider/mobile/mobile.go @@ -8,6 +8,7 @@ import ( "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/auth2" + "git.rosy.net.cn/jx-callback/business/auth2/authprovider" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/globals" "git.rosy.net.cn/jx-callback/globals/api" @@ -16,7 +17,6 @@ import ( const ( DefVerifyCodeDuration = 5 * time.Minute - TestMobile = "91112345678" TestVerifyCode = "123456" ) @@ -29,7 +29,7 @@ var ( ) type Auther struct { - auth2.DefAuther + authprovider.DefAuther } var ( @@ -62,7 +62,7 @@ func (a *Auther) VerifySecret(mobileNumber, code string) (authBind *model.AuthBi globals.SugarLogger.Debugf("VerifySecret mobileNumber:%s, code:%s", mobileNumber, code) err = ErrVerifyCodeIsWrong - if mobileNumber == TestMobile && code == TestVerifyCode { + if auth2.TestMobileMap[mobileNumber] == 1 && code == TestVerifyCode { err = nil } else { if value := api.Cacher.Get(mobileNumber); value != nil { diff --git a/business/auth2/authprovider/password/password.go b/business/auth2/authprovider/password/password.go index 282625bc2..f085f82fd 100644 --- a/business/auth2/authprovider/password/password.go +++ b/business/auth2/authprovider/password/password.go @@ -1,9 +1,13 @@ package password import ( + "crypto/sha1" "errors" + "fmt" + "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/auth2" + "git.rosy.net.cn/jx-callback/business/auth2/authprovider" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model/dao" ) @@ -13,7 +17,7 @@ const ( ) type Auther struct { - auth2.DefAuther + authprovider.DefAuther } var ( @@ -25,7 +29,7 @@ func init() { } func (a *Auther) VerifySecret(userID, passMD5 string) (authBind *model.AuthBind, err error) { - if authBind, err = dao.GetAuthBind(nil, "", AuthType, userID, ""); err == nil { + if authBind, err = dao.GetAuthBind(dao.GetDB(), "", AuthType, userID); err == nil { err = a.checkPassword(authBind, passMD5) } else if dao.IsNoRowsError(err) { err = auth2.ErrUserNotExist @@ -36,19 +40,30 @@ func (a *Auther) VerifySecret(userID, passMD5 string) (authBind *model.AuthBind, // 特殊接口 func (a *Auther) ChangePassword(userID, oldPassMD5, newPassMD5 string) (err error) { var authBind *model.AuthBind - if authBind, err = dao.GetAuthBind(nil, "", AuthType, userID, ""); err == nil { - if err = a.checkPassword(authBind, oldPassMD5); err == nil || authBind.AuthSecret == "" { + db := dao.GetDB() + if authBind, err = dao.GetAuthBind(db, "", AuthType, userID); err == nil { + if err = a.checkPassword(authBind, oldPassMD5); err == nil || authBind.AuthSecret == "" { // 如果原密码为空,不判断原密码,代表重置密码 authBind.AuthSecret = newPassMD5 - _, err = dao.UpdateEntity(nil, authBind, "AuthSecret") + _, err = dao.UpdateEntity(db, authBind, "AuthSecret") } } else if dao.IsNoRowsError(err) { - err = auth2.ErrUserNotExist + salt := utils.GetUUID() + err = a.AddAuthBind(&model.AuthBind{ + Type: AuthType, + AuthID: userID, + AuthSecret: a.encryptPassword(newPassMD5, salt), + AuthSecret2: salt, + }, "admin") } return err } +func (a *Auther) encryptPassword(password, salt string) string { + return fmt.Sprintf("%x", sha1.Sum([]byte(password+salt))) +} + func (a *Auther) checkPassword(authBind *model.AuthBind, passMD5 string) (err error) { - if authBind.AuthSecret != passMD5 { + if authBind.AuthSecret != a.encryptPassword(passMD5, authBind.AuthSecret2) { return ErrUserAndPassNotMatch } return nil diff --git a/business/auth2/authprovider/weixin/weixin.go b/business/auth2/authprovider/weixin/weixin.go index 33a25665a..4213b4c48 100644 --- a/business/auth2/authprovider/weixin/weixin.go +++ b/business/auth2/authprovider/weixin/weixin.go @@ -5,6 +5,7 @@ import ( "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/auth2" + "git.rosy.net.cn/jx-callback/business/auth2/authprovider" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model/dao" "git.rosy.net.cn/jx-callback/globals" @@ -13,12 +14,12 @@ import ( const ( AuthTypeWeixin = "weixin" - AuthTypeMP = "weixinmp" + AuthTypeMP = "weixinsns" AuthTypeMini = "weixinmini" ) type Auther struct { - auth2.DefAuther + authprovider.DefAuther authType string } @@ -51,10 +52,10 @@ func (a *Auther) VerifySecret(state, code string) (authBind *model.AuthBind, err wxUserinfo, err2 := api.WeixinAPI.SNSGetUserInfo(token.AccessToken, token.OpenID) if err = err2; err == nil { db := dao.GetDB() - if authBind, err = dao.GetAuthBind(db, "", a.authType, wxUserinfo.OpenID, ""); dao.IsNoRowsError(err) { + if authBind, err = dao.GetAuthBind(db, "", a.authType, wxUserinfo.OpenID); dao.IsNoRowsError(err) { var authBindList []*model.AuthBind if wxUserinfo.UnionID != "" { - if authBindList, err = dao.GetAuthBindsByWXUnionID(db, wxUserinfo.UnionID); err == nil && len(authBindList) > 0 { + if authBindList, err = dao.GetAuthBindsByAuthID2(db, wxUserinfo.UnionID, []string{AuthTypeWeixin, AuthTypeMP, AuthTypeMini}); err == nil && len(authBindList) > 0 { authBind = authBindList[0] authBind.Type = a.authType authBind.AuthID = wxUserinfo.OpenID diff --git a/business/auth2/authprovider/weixin/weixin_mini.go b/business/auth2/authprovider/weixin/weixin_mini.go index 25a398e1a..9a43b10ea 100644 --- a/business/auth2/authprovider/weixin/weixin_mini.go +++ b/business/auth2/authprovider/weixin/weixin_mini.go @@ -6,6 +6,7 @@ import ( "git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/jx-callback/business/auth2" + "git.rosy.net.cn/jx-callback/business/auth2/authprovider" "git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model/dao" "git.rosy.net.cn/jx-callback/globals" @@ -13,7 +14,7 @@ import ( ) type MiniAuther struct { - auth2.DefAuther + authprovider.DefAuther } var ( @@ -35,10 +36,10 @@ func (a *MiniAuther) VerifySecret(dummy, jsCode string) (authBind *model.AuthBin sessionInfo, err := api.WeixinMiniAPI.SNSCode2Session(jsCode) if err == nil { db := dao.GetDB() - if authBind, err = dao.GetAuthBind(db, "", AuthTypeMP, sessionInfo.OpenID, ""); dao.IsNoRowsError(err) { + if authBind, err = dao.GetAuthBind(db, "", AuthTypeMP, sessionInfo.OpenID); dao.IsNoRowsError(err) { var authBindList []*model.AuthBind if sessionInfo.UnionID != "" { - if authBindList, err = dao.GetAuthBindsByWXUnionID(db, sessionInfo.UnionID); err == nil && len(authBindList) > 0 { + if authBindList, err = dao.GetAuthBindsByAuthID2(db, sessionInfo.UnionID, []string{AuthTypeWeixin, AuthTypeMP, AuthTypeMini}); err == nil && len(authBindList) > 0 { authBind = authBindList[0] authBind.Type = AuthTypeMP authBind.AuthID = sessionInfo.OpenID diff --git a/business/jxstore/cms/user2.go b/business/jxstore/cms/user2.go new file mode 100644 index 000000000..d79764ad4 --- /dev/null +++ b/business/jxstore/cms/user2.go @@ -0,0 +1,59 @@ +package cms + +import ( + "errors" + + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/auth2" + "git.rosy.net.cn/jx-callback/business/model" + "git.rosy.net.cn/jx-callback/business/model/dao" +) + +var ( + ErrUserIDAndNameMustGiven = errors.New("用户ID2,用户名及手机号必须不为空") +) + +var ( + userProvider = &UserProvider{} + authTypeFieldMap = map[string]string{ + auth2.UserIDID: "user_id", + auth2.UserIDID2: "user_id2", + auth2.UserIDMobile: "mobile", + auth2.UserIDEmail: "email", + } +) + +type UserProvider struct { +} + +func (*UserProvider) GetUser(authID, authIDType string) (user auth2.IUser) { + fieldName := authTypeFieldMap[authIDType] + if fieldName != "" { + user, _ = dao.GetUserByID(dao.GetDB(), fieldName, authID) + } + return user +} + +func init() { + auth2.Init(userProvider) +} + +func RegisterUser(user *model.User, mobileVerifyCode string, inAuthInfo *auth2.AuthInfo) (outAuthInfo *auth2.AuthInfo, err error) { + if user == nil || user.UserID2 == "" || user.Name == "" || user.Mobile == "" { + return nil, ErrUserIDAndNameMustGiven + } + mobileAuth, err2 := auth2.Login(auth2.AuthTypeMobile, user.Mobile, auth2.UserIDNone, mobileVerifyCode) + if err = err2; err == nil { + if mobileAuth.IUser != nil { + return nil, auth2.ErrUserAlreadyExist + } + dao.WrapAddIDCULDEntity(user, "RegisterUser") + user.UserID = utils.GetUUID() + if err = dao.CreateEntity(nil, user); err == nil { + if outAuthInfo, err = auth2.BindUser(mobileAuth, user); err == nil && inAuthInfo != nil { + err = auth2.AddAuthBind(outAuthInfo, inAuthInfo) + } + } + } + return outAuthInfo, err +} diff --git a/business/jxutils/jxcontext/jxcontext.go b/business/jxutils/jxcontext/jxcontext.go index 016c0369c..c90222db0 100644 --- a/business/jxutils/jxcontext/jxcontext.go +++ b/business/jxutils/jxcontext/jxcontext.go @@ -64,7 +64,7 @@ func New(rootTask tasksch.ITask, token string, w http.ResponseWriter, r *http.Re accessUUID: utils.GetUUID(), } if auth2.IsV2Token(token) { - authInfo, err2 := auth2.GetUserInfo(token) + authInfo, err2 := auth2.GetTokenInfo(token) if err = err2; err == nil { ctx.userInfo = authInfo if authInfo.TokenType != auth2.TokenTypeNormal { diff --git a/business/model/auth2.go b/business/model/auth2.go index 35cc27cc4..ba2904b1f 100644 --- a/business/model/auth2.go +++ b/business/model/auth2.go @@ -12,8 +12,8 @@ type AuthBind struct { Type string `orm:"size(16)" json:"type"` Status int8 `json:"status"` - AuthID string `orm:"size(48);index" json:"authID"` - AuthID2 string `orm:"size(48);index" json:"authID2"` + AuthID string `orm:"size(48);column(auth_id);index" json:"authID"` + AuthID2 string `orm:"size(48);column(auth_id2);index" json:"authID2"` AuthSecret string `orm:"size(48)" json:"authSecret"` AuthSecret2 string `orm:"size(48)" json:"authSecret2"` Remark string `orm:"size(255)" json:"remark"` diff --git a/business/model/dao/dao_auth2.go b/business/model/dao/dao_auth2.go index 03144b95a..239d73839 100644 --- a/business/model/dao/dao_auth2.go +++ b/business/model/dao/dao_auth2.go @@ -1,11 +1,50 @@ package dao -import "git.rosy.net.cn/jx-callback/business/model" +import ( + "errors" -func GetAuthBind(db *DaoDB, userID, authType, authID, authID2 string) (authBind *model.AuthBind, err error) { + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/model" +) + +func GetAuthBind(db *DaoDB, userID, authType, authID string) (authBind *model.AuthBind, err error) { + if userID == "" && authID == "" { + return nil, errors.New("userID, authID, authID2不能全为空") + } + sql := ` + SELECT * + FROM auth_bind t1 + WHERE t1.deleted_at = ? + ` + sqlParams := []interface{}{ + utils.DefaultTimeValue, + } + if userID != "" { + sql += " AND t1.user_id = ?" + sqlParams = append(sqlParams, userID) + } + if authType != "" { + sql += " AND t1.type = ?" + sqlParams = append(sqlParams, authType) + } + if authID != "" { + sql += " AND t1.auth_id = ?" + sqlParams = append(sqlParams, authID) + } + err = GetRow(db, &authBind, sql, sqlParams...) return authBind, err } -func GetAuthBindsByWXUnionID(db *DaoDB, unionID string) (authBinds []*model.AuthBind, err error) { +func GetAuthBindsByAuthID2(db *DaoDB, authID2 string, typeList []string) (authBinds []*model.AuthBind, err error) { + sql := ` + SELECT * + FROM auth_bind t1 + WHERE t1.deleted_at = ? AND t1.auth_id2 = ? AND t1.type IN (` + GenQuestionMarks(len(typeList)) + ")" + sqlParams := []interface{}{ + utils.DefaultTimeValue, + authID2, + typeList, + } + err = GetRows(db, &authBinds, sql, sqlParams...) return authBinds, err } diff --git a/business/model/dao/dao_user2.go b/business/model/dao/dao_user2.go new file mode 100644 index 000000000..f21d58a7e --- /dev/null +++ b/business/model/dao/dao_user2.go @@ -0,0 +1,18 @@ +package dao + +import ( + "fmt" + + "git.rosy.net.cn/baseapi/utils" + "git.rosy.net.cn/jx-callback/business/model" +) + +func GetUserByID(db *DaoDB, fieldName, fieldValue string) (user *model.User, err error) { + sql := fmt.Sprintf(` + SELECT * + FROM user t1 + WHERE t1.deleted_at = ? AND t1.%s = ? + `, fieldName) + err = GetRows(db, &user, sql, utils.DefaultTimeValue, fieldValue) + return user, err +} diff --git a/controllers/auth2.go b/controllers/auth2.go index 6db9107d0..940cf76e2 100644 --- a/controllers/auth2.go +++ b/controllers/auth2.go @@ -23,25 +23,42 @@ type Auth2Controller struct { beego.Controller } +// @Title 生成captcha +// @Description 生成captcha +// @Param width formData int true "图片宽" +// @Param height formData int true "图片高" +// @Param captchaLen formData int false "验证码长度" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /CreateCaptcha [post] +func (c *Auth2Controller) CreateCaptcha() { + c.callCreateCaptcha(func(params *tAuth2CreateCaptchaParams) (retVal interface{}, errCode string, err error) { + retVal, err = auth2.CreateCaptcha(params.Width, params.Height, params.CaptchaLen) + return retVal, "", err + }) +} + // @Title 发送验证码 // @Description 发送验证码 +// @Param captchaID formData string true "图片验证码ID" +// @Param captchaValue formData string true "图片验证码值" // @Param authID formData string true "手机号或邮件" // @Success 200 {object} controllers.CallResult // @Failure 200 {object} controllers.CallResult // @router /SendVerifyCode [post] func (c *Auth2Controller) SendVerifyCode() { c.callSendVerifyCode(func(params *tAuth2SendVerifyCodeParams) (retVal interface{}, errCode string, err error) { - err = auth2.SendVerifyCode(params.AuthID) + err = auth2.SendVerifyCode(params.CaptchaID, params.CaptchaValue, params.AuthID) return retVal, "", err }) } // @Title 登录接口 // @Description 登录接口(微信与公众号登录不能直接调用此接口) -// @Param authType formData string true "登录类型,当前支持[password:本地账号密码,mobile:手机短信,weixin:微信登录,weixinmp:微信公众号登录,weixinmini;小程序登录]" -// @Param authSecret formData string true "不同登录类型的登录秘密" -// @Param authID formData string false "登录ID,登录类型为password时依赖于authIDType,其它为相应登录类型的id" -// @Param authIDType formData string false "只有在登录类型为password时,才有意义,分别为:userID2:用户名,email,mobile" +// @Param authType formData string true "登录类型,当前支持[localpass:本地账号密码,mobile:手机短信,weixin:微信登录,weixinsns:微信公众号登录,weixinmini;小程序登录]" +// @Param authSecret formData string true "不同登录类型的登录秘密,如果是localpass登录类型,是md5后的值(空串不要md5)" +// @Param authID formData string false "登录ID,登录类型为localpass时依赖于authIDType,其它为相应登录类型的id" +// @Param authIDType formData string false "只有在登录类型为localpass时,才有意义,分别为:userID2:用户名,email,mobile" // @Success 200 {object} controllers.CallResult // @Failure 200 {object} controllers.CallResult // @router /Login [post] @@ -140,7 +157,7 @@ func (c *Auth2Controller) AddAuthBind() { c.callAddAuthBind(func(params *tAuth2AddAuthBindParams) (retVal interface{}, errCode string, err error) { authInfo, err2 := c.getAuth2Info(params.Ctx) if err := err2; err == nil { - newAuthInfo, err2 := auth2.GetUserInfo(params.AuthToken) + newAuthInfo, err2 := auth2.GetTokenInfo(params.AuthToken) if err = err2; err == nil { err = auth2.AddAuthBind(authInfo, newAuthInfo) } @@ -152,7 +169,7 @@ func (c *Auth2Controller) AddAuthBind() { // @Title 删除认证方式 // @Description 删除认证方式 // @Param token header string true "认证token" -// @Param authType formData string true "登录类型,当前支持[weixin:微信登录,weixinmp:微信公众号登录,weixinmini;小程序登录]" +// @Param authType formData string true "登录类型,当前支持[weixin:微信登录,weixinsns:微信公众号登录,weixinmini;小程序登录]" // @Success 200 {object} controllers.CallResult // @Failure 200 {object} controllers.CallResult // @router /RemoveAuthBind [post] @@ -166,6 +183,20 @@ func (c *Auth2Controller) RemoveAuthBind() { }) } +// @Title 修改(或初始化)密码 +// @Description 修改(或初始化)密码 +// @Param token header string true "认证token" +// @Param oldPwd query string false "原密码md5,如果是重置或新设,为空" +// @Param newPwd query string true "新密码md5" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /ChangePassword [put] +func (c *Auth2Controller) ChangePassword() { + c.callChangePassword(func(params *tAuth2ChangePasswordParams) (retVal interface{}, errCode string, err error) { + return retVal, "", err + }) +} + func (c *Auth2Controller) getAuth2Info(ctx *jxcontext.Context) (authInfo *auth2.AuthInfo, err error) { if authInfo, ok := ctx.GetLoginInfo().(*auth2.AuthInfo); ok { return authInfo, err diff --git a/controllers/cms_user2.go b/controllers/cms_user2.go new file mode 100644 index 000000000..bc596d79c --- /dev/null +++ b/controllers/cms_user2.go @@ -0,0 +1,41 @@ +package controllers + +import ( + "git.rosy.net.cn/jx-callback/business/auth2" + _ "git.rosy.net.cn/jx-callback/business/auth2/authprovider/mobile" + _ "git.rosy.net.cn/jx-callback/business/auth2/authprovider/password" + "git.rosy.net.cn/jx-callback/business/jxstore/cms" + "git.rosy.net.cn/jx-callback/business/jxutils" + "git.rosy.net.cn/jx-callback/business/model" + "github.com/astaxie/beego" +) + +type User2Controller struct { + beego.Controller +} + +// @Title 用户注册 +// @Description 用户注册 +// @Param payload formData string true "json数据,User对象(手机号必填)" +// @Param mobileVerifyCode formData string true "手机验证码(通过auth2.SendVerifyCode获得)" +// @Param authToken formData string false "之前通过login得到的认证TOKEN(可以为空)" +// @Success 200 {object} controllers.CallResult +// @Failure 200 {object} controllers.CallResult +// @router /RegisterUser [post] +func (c *User2Controller) RegisterUser() { + c.callRegisterUser(func(params *tUser2RegisterUserParams) (retVal interface{}, errCode string, err error) { + var ( + user model.User + inAuthInfo *auth2.AuthInfo + ) + if params.AuthToken != "" { + inAuthInfo, err = auth2.GetTokenInfo(params.AuthToken) + } + if err == nil { + if err = jxutils.Strings2Objs(params.Payload, &user); err == nil { + retVal, err = cms.RegisterUser(&user, params.MobileVerifyCode, inAuthInfo) + } + } + return retVal, "", err + }) +} diff --git a/globals/beegodb/beegodb.go b/globals/beegodb/beegodb.go index ca76b05ea..2c930bdd6 100644 --- a/globals/beegodb/beegodb.go +++ b/globals/beegodb/beegodb.go @@ -35,6 +35,7 @@ func Init() { // orm.RegisterModel(&model.DurableTask{}, &model.DurableTaskItem{}) orm.RegisterModel(&model.Promotion{}, &model.PromotionStore{}, &model.PromotionSku{}) + orm.RegisterModel(&model.AuthBind{}, &model.User{}) if globals.EnablePendingChange { orm.RegisterModel(&model.StoreOpRequest{}) diff --git a/routers/commentsRouter_controllers.go b/routers/commentsRouter_controllers.go index ec4299f07..acc2fbbd6 100644 --- a/routers/commentsRouter_controllers.go +++ b/routers/commentsRouter_controllers.go @@ -15,6 +15,22 @@ func init() { MethodParams: param.Make(), Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"], + beego.ControllerComments{ + Method: "ChangePassword", + Router: `/ChangePassword`, + AllowHTTPMethods: []string{"put"}, + MethodParams: param.Make(), + Params: nil}) + + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"], + beego.ControllerComments{ + Method: "CreateCaptcha", + Router: `/CreateCaptcha`, + AllowHTTPMethods: []string{"post"}, + MethodParams: param.Make(), + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:Auth2Controller"], beego.ControllerComments{ Method: "Login", @@ -967,6 +983,14 @@ func init() { MethodParams: param.Make(), Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:User2Controller"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:User2Controller"], + beego.ControllerComments{ + Method: "RegisterUser", + Router: `/RegisterUser`, + AllowHTTPMethods: []string{"post"}, + MethodParams: param.Make(), + Params: nil}) + beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:UserController"] = append(beego.GlobalControllerRouter["git.rosy.net.cn/jx-callback/controllers:UserController"], beego.ControllerComments{ Method: "TmpAddMobile2Mobile", diff --git a/routers/router.go b/routers/router.go index 4eff77782..5f7725ab2 100644 --- a/routers/router.go +++ b/routers/router.go @@ -86,6 +86,11 @@ func init() { &controllers.Auth2Controller{}, ), ), + beego.NSNamespace("/user2", + beego.NSInclude( + &controllers.User2Controller{}, + ), + ), ) beego.AddNamespace(ns)