- dingding auth

This commit is contained in:
gazebo
2019-03-07 21:15:19 +08:00
parent 123ffd4353
commit ce109a60b3
16 changed files with 238 additions and 85 deletions

View File

@@ -53,6 +53,7 @@ type IUserProvider interface {
GetUser(authID, authIDType string) (user IUser)
UpdateUserMobile(userID string, mobile string) (err error)
UpdateUserEmail(userID string, email string) (err error)
CreateUser(userID2, mobile, email, name string) (user IUser, err error)
}
type CaptchaInfo struct {
@@ -63,8 +64,8 @@ type CaptchaInfo struct {
type IAuther interface {
SendVerifyCode(authID string) (err error)
// 负责验证secret并找到相应的用户返回password,email,mobile类型的不负责用户查找如果找不到用户UserID为空
VerifySecret(authID, authSecret string) (authBind *model.AuthBind, err error)
AddAuthBind(authBind *model.AuthBind, userName string) (err error)
VerifySecret(authID, authSecret string) (authBindEx *AuthBindEx, err error)
AddAuthBind(authBindEx *AuthBindEx, userName string) (err error)
UnbindAuth(authInfo *AuthInfo, authType string) (err error)
Logout(authInfo *AuthInfo) (err error)
}
@@ -110,7 +111,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 *AuthBindEx) (authInfo *AuthInfo) {
token, tokenType := createToken(user)
authInfo = &AuthInfo{
AuthBindInfo: authBindInfo,
@@ -119,7 +120,6 @@ func CreateAuthInfo(user IUser, authBindInfo *model.AuthBind, userData interface
ExpiresIn: time.Now().Add(DefTokenDuration).Unix(),
Token: token,
TokenType: tokenType,
UserData: userData,
}
if user != nil {
authInfo.UpdateByIUser(user)
@@ -177,7 +177,7 @@ func Login(authType, authID, authIDType, authSecret string) (authInfo *AuthInfo,
authType = strings.ToLower(authType)
authIDType = strings.ToLower(authIDType)
if handler := authers[authType]; handler != nil {
var authBind *model.AuthBind
var authBindEx *AuthBindEx
var user IUser
realAuthID := authID
if authType == AuthTypePassword {
@@ -189,21 +189,33 @@ func Login(authType, authID, authIDType, authSecret string) (authInfo *AuthInfo,
}
realAuthID = user.GetID()
}
if authBind, err = handler.VerifySecret(realAuthID, authSecret); err == nil {
if authBind == nil { // mobile, email会返回nil表示不会新建AuthBind实体
if authBindEx, err = handler.VerifySecret(realAuthID, authSecret); err == nil {
if authBindEx == nil { // mobile, email会返回nil表示不会新建AuthBind实体
user = userProvider.GetUser(authID, authIDType)
authBind = &model.AuthBind{
authBindEx = &AuthBindEx{
AuthBind: model.AuthBind{
Type: authType,
AuthID: authID,
Status: model.AuthBindStatusNormal,
},
}
} else {
// 返回authBind中UserID为空表示只是认证但本地没有记录这种情况会返回临时TOKEN
if authBind.UserID != "" {
user = userProvider.GetUser(authBind.UserID, UserIDID)
if authBindEx.UserHint != nil && authBindEx.UserID == "" {
if authBindEx.UserHint.Mobile != "" {
user = userProvider.GetUser(authBindEx.UserHint.Mobile, UserIDMobile)
}
if user == nil && authBindEx.UserHint.Email != "" {
user = userProvider.GetUser(authBindEx.UserHint.Email, UserIDEmail)
}
if user != nil {
authBindEx.UserID = user.GetID()
}
} else if authBindEx.UserID != "" {
user = userProvider.GetUser(authBindEx.UserID, UserIDID)
}
}
authInfo = CreateAuthInfo(user, authBind, nil)
authInfo = createAuthInfo(user, authBindEx)
}
} else {
err = ErrIllegalAuthType
@@ -223,7 +235,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)
}
} else {
err = ErrIllegalAuthType

View File

@@ -53,15 +53,20 @@ func (u *UserBasic) IsUserEmpty() bool {
return u.UserID == ""
}
type AuthBindEx struct {
model.AuthBind
UserData interface{}
UserHint *UserBasic
}
type AuthInfo struct {
UserBasic
AuthBindInfo *model.AuthBind
AuthBindInfo *AuthBindEx
LoginTime time.Time
ExpiresIn int64
Token string
TokenType int // TOKEN类型
UserData interface{}
}
func (a *AuthInfo) GetAuthID() string {

View File

@@ -13,10 +13,10 @@ type DefAuther struct {
}
// 此函数为空
func (a *DefAuther) AddAuthBind(authBind *model.AuthBind, userName string) (err error) {
dao.WrapAddIDCULDEntity(authBind, userName)
authBind.Status = model.AuthBindStatusNormal
err = dao.CreateEntity(nil, authBind)
func (a *DefAuther) AddAuthBind(authBindEx *auth2.AuthBindEx, userName string) (err error) {
dao.WrapAddIDCULDEntity(authBindEx, userName)
authBindEx.Status = model.AuthBindStatusNormal
err = dao.CreateEntity(nil, authBindEx.AuthBind)
return err
}

View File

@@ -0,0 +1,6 @@
package dingding
const (
AuthTypeDingDing = "dingding"
AuthTypeStaff = "ddstaff" // 钉钉企业登录
)

View File

@@ -0,0 +1,74 @@
package dingding
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"
"git.rosy.net.cn/jx-callback/globals/api"
)
type StaffAuther struct {
authprovider.DefAuther
}
var (
AutherObjStaff *StaffAuther
)
func init() {
AutherObjStaff = new(StaffAuther)
auth2.RegisterAuther(AuthTypeStaff, AutherObjStaff)
}
func (a *StaffAuther) VerifySecret(dummy, code string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("dingding staff VerifySecret code:%s", code)
userID, err := api.DingDingAPI.GetUserID(code)
if err == nil {
db := dao.GetDB()
var authBind *model.AuthBind
if authBind, err = dao.GetAuthBind(db, "", AuthTypeStaff, userID.UserID); dao.IsNoRowsError(err) {
userDetail, err2 := api.DingDingAPI.GetUserDetail(userID.UserID)
if err = err2; err == nil {
userHint := &auth2.UserBasic{
UserID2: userID.UserID,
Mobile: utils.Interface2String(userDetail["mobile"]),
Email: utils.Interface2String(userDetail["email"]),
Name: utils.Interface2String(userDetail["name"]),
}
unionID := utils.Interface2String(userDetail["unionid"])
if unionID != "" {
var authBindList []*model.AuthBind
if authBindList, err = dao.GetAuthBindsByAuthID2(db, unionID, []string{AuthTypeDingDing, AuthTypeStaff}); err == nil && len(authBindList) > 0 {
authBind = authBindList[0]
authBind.Type = AuthTypeStaff
authBind.AuthID = userID.UserID
authBind.DetailData = string(utils.MustMarshal(userDetail))
authBindEx = &auth2.AuthBindEx{
AuthBind: *authBind,
UserHint: userHint,
}
err = a.AddAuthBind(authBindEx, "admin")
} else if dao.IsNoRowsError(err) {
err = nil
}
}
if err == nil && authBindEx == nil {
authBindEx = &auth2.AuthBindEx{
AuthBind: model.AuthBind{
Type: AuthTypeStaff,
AuthID: userID.UserID,
AuthID2: unionID,
DetailData: string(utils.MustMarshal(userDetail)),
},
UserHint: userHint,
}
}
}
}
}
return authBindEx, err
}

View File

@@ -9,7 +9,6 @@ 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"
"github.com/KenmyZhang/aliyun-communicate"
@@ -58,7 +57,7 @@ func (a *Auther) SendVerifyCode(mobileNumber string) error {
return err
}
func (a *Auther) VerifySecret(mobileNumber, code string) (authBind *model.AuthBind, err error) {
func (a *Auther) VerifySecret(mobileNumber, code string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("VerifySecret mobileNumber:%s, code:%s", mobileNumber, code)
err = ErrVerifyCodeIsWrong
@@ -76,7 +75,7 @@ func (a *Auther) VerifySecret(mobileNumber, code string) (authBind *model.AuthBi
}
// 此函数为空
func (a *Auther) AddAuthBind(authBind *model.AuthBind, userName string) (err error) {
func (a *Auther) AddAuthBind(authBindEx *auth2.AuthBindEx, userName string) (err error) {
return err
}

View File

@@ -34,14 +34,19 @@ func init() {
auth2.RegisterAuther(AuthType, AutherObj)
}
func (a *Auther) VerifySecret(userID, passMD5 string) (authBind *model.AuthBind, err error) {
func (a *Auther) VerifySecret(userID, passMD5 string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("localpass VerifySecret userID:%s", userID)
var authBind *model.AuthBind
if authBind, err = dao.GetAuthBind(dao.GetDB(), "", AuthType, userID); err == nil {
err = a.checkPassword(authBind, passMD5)
if err = a.checkPassword(authBind, passMD5); err == nil {
authBindEx = &auth2.AuthBindEx{
AuthBind: *authBind,
}
}
} else if dao.IsNoRowsError(err) {
err = auth2.ErrUserAuthTypeNotExist
}
return authBind, err
return authBindEx, err
}
// 特殊接口
@@ -58,12 +63,14 @@ func (a *Auther) ChangePassword(userID, oldPassMD5, newPassMD5 string) (err erro
}, "admin", nil)
}
} else if dao.IsNoRowsError(err) {
err = a.AddAuthBind(&model.AuthBind{
err = a.AddAuthBind(&auth2.AuthBindEx{
AuthBind: model.AuthBind{
UserID: userID,
Type: AuthType,
AuthID: userID,
AuthSecret: encryptPwd,
AuthSecret2: salt,
},
}, "admin")
}
return err

View File

@@ -44,7 +44,7 @@ func init() {
auth2.RegisterAuther(AuthTypeMP, AutherObjMP)
}
func (a *Auther) VerifySecret(state, code string) (authBind *model.AuthBind, err error) {
func (a *Auther) VerifySecret(state, code string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("weixin VerifySecret code:%s", code)
if state == "" {
token, err2 := api.WeixinPageAPI.SNSRetrieveToken(code)
@@ -52,25 +52,29 @@ func (a *Auther) VerifySecret(state, code string) (authBind *model.AuthBind, err
wxUserinfo, err2 := api.WeixinPageAPI.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) {
var authBind *model.AuthBind
if authBind, err = dao.GetAuthBind(db, "", a.authType, wxUserinfo.OpenID); dao.IsNoRowsError(err) && wxUserinfo.UnionID != "" {
var authBindList []*model.AuthBind
if wxUserinfo.UnionID != "" {
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
authBind.DetailData = string(utils.MustMarshal(wxUserinfo))
err = a.AddAuthBind(authBind, wxUserinfo.NickName)
authBindEx = &auth2.AuthBindEx{
AuthBind: *authBind,
}
err = a.AddAuthBind(authBindEx, wxUserinfo.NickName)
} else if dao.IsNoRowsError(err) {
err = auth2.ErrUserAuthTypeNotExist
err = nil
}
}
if err == nil && len(authBindList) == 0 {
authBind = &model.AuthBind{
if err == nil && authBindEx == nil {
authBindEx = &auth2.AuthBindEx{
AuthBind: model.AuthBind{
Type: a.authType,
AuthID: wxUserinfo.OpenID,
AuthID2: wxUserinfo.UnionID,
DetailData: string(utils.MustMarshal(wxUserinfo)),
},
}
}
}
@@ -79,5 +83,5 @@ func (a *Auther) VerifySecret(state, code string) (authBind *model.AuthBind, err
} else {
err = ErrStateIsWrong
}
return authBind, err
return authBindEx, err
}

View File

@@ -30,40 +30,44 @@ func init() {
auth2.RegisterAuther(AuthTypeMini, AutherObjMini)
}
func (a *MiniAuther) VerifySecret(dummy, jsCode string) (authBind *model.AuthBind, err error) {
func (a *MiniAuther) VerifySecret(dummy, jsCode string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("weixin mini VerifySecret jsCode:%s", jsCode)
sessionInfo, err := api.WeixinMiniAPI.SNSCode2Session(jsCode)
if err == nil {
db := dao.GetDB()
if authBind, err = dao.GetAuthBind(db, "", AuthTypeMini, sessionInfo.OpenID); dao.IsNoRowsError(err) {
var authBind *model.AuthBind
if authBind, err = dao.GetAuthBind(db, "", AuthTypeMini, sessionInfo.OpenID); dao.IsNoRowsError(err) && sessionInfo.UnionID != "" {
var authBindList []*model.AuthBind
sessionKey := sessionInfo.SessionKey
sessionInfo.SessionKey = ""
if sessionInfo.UnionID != "" {
if authBindList, err = dao.GetAuthBindsByAuthID2(db, sessionInfo.UnionID, []string{AuthTypeWeixin, AuthTypeMini, AuthTypeMini}); err == nil && len(authBindList) > 0 {
authBind = authBindList[0]
authBind.Type = AuthTypeMini
authBind.AuthID = sessionInfo.OpenID
authBind.DetailData = string(utils.MustMarshal(sessionInfo))
authBind.UserData = sessionKey
err = a.AddAuthBind(authBind, "admin")
authBindEx = &auth2.AuthBindEx{
AuthBind: *authBind,
UserData: sessionKey,
}
err = a.AddAuthBind(authBindEx, "admin")
} else if dao.IsNoRowsError(err) {
err = auth2.ErrUserAuthTypeNotExist
err = nil
}
}
if err == nil && len(authBindList) == 0 {
authBind = &model.AuthBind{
if err == nil && authBindEx == nil {
authBindEx = &auth2.AuthBindEx{
AuthBind: model.AuthBind{
Type: AuthTypeMini,
AuthID: sessionInfo.OpenID,
AuthID2: sessionInfo.UnionID,
DetailData: string(utils.MustMarshal(sessionInfo)),
},
UserData: sessionKey,
}
}
}
}
return authBind, err
return authBindEx, err
}
// 特殊接口

View File

@@ -58,24 +58,28 @@ func (*UserProvider) UpdateUserEmail(userID string, email string) (err error) {
return err
}
func (*UserProvider) CreateUser(userID2, mobile, email, name string) (user auth2.IUser, err error) {
realUser := &model.User{
UserID2: userID2,
Mobile: mobile,
Email: email,
Name: name,
}
return realUser, CreateUser(realUser)
}
func init() {
auth2.Init(userProvider)
}
func RegisterUser(user *model.User, mobileVerifyCode string, inAuthInfo *auth2.AuthInfo) (outAuthInfo *auth2.AuthInfo, errCode string, err error) {
errCode = model.ErrCodeGeneralFailed
if user == nil || user.UserID2 == "" || user.Name == "" || user.Mobile == "" {
return nil, model.ErrCodeGeneralFailed, ErrUserIDAndNameMustGiven
}
mobileAuth, err2 := auth2.Login(auth2.AuthTypeMobile, user.Mobile, auth2.UserIDMobile, mobileVerifyCode)
if err = err2; err == nil {
if !mobileAuth.IsUserEmpty() {
return nil, model.ErrCodeUserAlreadyExist, auth2.ErrUserMobileAlreadyExist
}
dao.WrapAddIDCULDEntity(user, "RegisterUser")
user.UserID = utils.GetUUID()
user.Status = model.UserStatusNormal
if err = dao.CreateEntity(nil, user); err == nil {
if err = CreateUser(user); err == nil {
if outAuthInfo, err = auth2.BindUser(mobileAuth, user); err == nil && inAuthInfo != nil {
err = auth2.AddAuthBind(outAuthInfo, inAuthInfo)
}
@@ -97,3 +101,13 @@ func GetUserBindAuthInfo(ctx *jxcontext.Context) (authList []*model.AuthBind, er
}
return nil, err
}
func CreateUser(user *model.User) (err error) {
if user == nil || user.UserID2 == "" || user.Name == "" || user.Mobile == "" {
return ErrUserIDAndNameMustGiven
}
dao.WrapAddIDCULDEntity(user, "RegisterUser")
user.UserID = utils.GetUUID()
user.Status = model.UserStatusNormal
return dao.CreateEntity(nil, user)
}

View File

@@ -17,6 +17,7 @@ import (
const (
weixinTokenExpires = 7200 * time.Second
dingdingTokenExpires = 7200 * time.Second
elmTokenExpires = 20 * 24 * 3600 * time.Second
weimobTokenExpires = 7200 * time.Second
maxRefreshGap = 5 * 60 * time.Second
@@ -106,7 +107,7 @@ func RefreshWeixinToken() error {
return RefreshConfig("wechat", weixinTokenExpires, func() (string, string) {
globals.SugarLogger.Debugf("RefreshWeixinToken RunMode:%s", beego.BConfig.RunMode)
if beego.BConfig.RunMode == "prod" {
if tokenInfo, err := api.WeixinAPI.CBRefreshToken(); err == nil {
if tokenInfo, err := api.WeixinAPI.CBRetrieveToken(); err == nil {
globals.SugarLogger.Debugf("RefreshWeixinToken tokenInfo:%s", utils.Format4Output(tokenInfo, true))
return tokenInfo.AccessToken, ""
} else {
@@ -162,6 +163,23 @@ func RefreshWeimobToken() error {
})
}
func RefreshDingDingToken() error {
return RefreshConfig("dingding", dingdingTokenExpires, func() (string, string) {
globals.SugarLogger.Debugf("RefreshDingDingToken RunMode:%s", beego.BConfig.RunMode)
if beego.BConfig.RunMode == "prod" {
if token, err := api.DingDingAPI.RetrieveToken(); err == nil {
globals.SugarLogger.Debugf("RefreshDingDingToken tokenInfo:%s", token)
return token, ""
} else {
globals.SugarLogger.Errorf("RefreshDingDingToken RefreshToken failed with error:%v", err)
}
}
return "", ""
}, func(value string) {
api.DingDingAPI.SetToken(value)
})
}
func SaveWeimobToken(token *weimobapi.TokenInfo) (err error) {
db := dao.GetDB()
config := &legacymodel.Config{

View File

@@ -18,8 +18,6 @@ type AuthBind struct {
AuthSecret2 string `orm:"size(48)" json:"-"`
Remark string `orm:"size(255)" json:"remark"`
DetailData string `orm:"type(text)" json:"detailData"`
UserData interface{} `orm:"-" json:"-"`
}
func (*AuthBind) TableUnique() [][]string {

View File

@@ -54,6 +54,9 @@ weimobCallbackURL = "http://callback.test.jxc4.com/weimob"
weixinPageAppID = "wx018dbe7daa3d5627"
weixinPageSecret = "c7a84ed3ef3ae04ac78e02fb593ffbe5"
dingdingAppKey = "ding7iu9cptairtcls0c"
dingdingSecret = "LWrZAFeqUfuVv7n_tc8vPpCAx6PT4CwManx2XCVhJOqGsx2L5XCDuX1sAN_JtvsI"
[dev]
jdToken = "c8854ef2-f80a-45ee-aceb-dc8014d646f8"
jdAppKey = "06692746f7224695ad4788ce340bc854"

View File

@@ -2,6 +2,7 @@ package controllers
import (
"git.rosy.net.cn/jx-callback/business/auth2"
_ "git.rosy.net.cn/jx-callback/business/auth2/authprovider/dingding"
_ "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"

View File

@@ -6,6 +6,7 @@ import (
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/baseapi/platformapi/autonavi"
"git.rosy.net.cn/baseapi/platformapi/dadaapi"
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/platformapi/elmapi"
"git.rosy.net.cn/baseapi/platformapi/jdapi"
@@ -36,6 +37,7 @@ var (
QiniuAPI *qbox.Mac
ShowAPI *showapi.API
WeimobAPI *weimobapi.API
DingDingAPI *dingdingapi.API
Cacher cache.ICacher
)
@@ -86,6 +88,8 @@ func Init() {
weimobAPIConfig := platformapi.DefAPIConfig
weimobAPIConfig.ClientTimeout = 120 * time.Second
WeimobAPI = weimobapi.New(nil, beego.AppConfig.DefaultString("weimobAppID", ""), beego.AppConfig.DefaultString("weimobAppSecret", ""), &weimobAPIConfig)
DingDingAPI = dingdingapi.New(beego.AppConfig.DefaultString("dingdingAppKey", ""), beego.AppConfig.DefaultString("dingdingSecret", ""))
}
func initElm() {

View File

@@ -93,6 +93,10 @@ func main() {
globals.SugarLogger.Errorf("RefreshWeimobToken failed with error:%s", err)
return
}
if err := tasks.RefreshDingDingToken(); err != nil {
globals.SugarLogger.Errorf("RefreshDingDingToken failed with error:%s", err)
return
}
orderman.LoadPendingOrders()
if beego.BConfig.RunMode != "prod" {