- v2 token format changed

- DisableUser
- clear all tokens when disable user
- handle ding ding user leave event
This commit is contained in:
gazebo
2019-03-09 20:59:18 +08:00
parent 4b362baea9
commit 2e65154206
6 changed files with 117 additions and 21 deletions

View File

@@ -10,6 +10,7 @@ import (
"git.rosy.net.cn/baseapi/utils"
"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"
"github.com/dchest/captcha"
@@ -24,6 +25,7 @@ const (
)
const (
TokenHeader = "TOKEN"
TokenVer = "V2"
TokenTypeSep = "."
TokenUserEmpty = "NULL"
@@ -37,8 +39,11 @@ const (
)
const (
DefTokenDuration = 7 * 24 * time.Hour // 7天
DefTokenDuration = 7 * 24 * time.Hour // 正式TOKEN7天有效期
TmpTokenDuration = 30 * time.Minute // 临时TOKEN30分钟有效期
MinCaptchaLen = 4
MaxCaptchaWidth = 400
MaxCaptchaHeight = 400
)
type IUser interface {
@@ -113,9 +118,9 @@ func RegisterAuther(authType string, handler IAuther) {
func createAuthInfo(user IUser, authBindInfo *AuthBindEx) (authInfo *AuthInfo) {
token, tokenType := createToken(user)
expireDuration := DefTokenDuration
authInfo = &AuthInfo{
AuthBindInfo: authBindInfo,
LoginTime: time.Now(),
ExpiresIn: time.Now().Add(DefTokenDuration).Unix(),
Token: token,
@@ -125,9 +130,11 @@ func createAuthInfo(user IUser, authBindInfo *AuthBindEx) (authInfo *AuthInfo) {
authInfo.UpdateByIUser(user)
globals.SugarLogger.Debugf("createAuthInfo id:%s, id2:%s, mobile:%s, authInfo:%s", authInfo.GetID(), authInfo.GetID2(), authInfo.GetMobile(), utils.Format4Output(authInfo, true))
} else {
expireDuration = TmpTokenDuration
authInfo.ExpiresIn = time.Now().Add(expireDuration).Unix()
globals.SugarLogger.Debugf("createAuthInfo authInfo:%s", utils.Format4Output(authInfo, true))
}
SetUserInfo(token, authInfo, DefTokenDuration)
SetUserInfo(token, authInfo, expireDuration)
return authInfo
}
@@ -135,6 +142,12 @@ func CreateCaptcha(width, height, captchaLen int) (captchaInfo *CaptchaInfo, err
if captchaLen < MinCaptchaLen {
captchaLen = MinCaptchaLen
}
if width > MaxCaptchaWidth {
width = MaxCaptchaWidth
}
if height > MaxCaptchaHeight {
height = MaxCaptchaHeight
}
captchaInfo = &CaptchaInfo{
ID: captcha.NewLen(captchaLen),
}
@@ -283,6 +296,7 @@ func Logout(authInfo *AuthInfo) (err error) {
}
// token缓存相关
/////////////
func RemoveUserInfo(token string) {
api.Cacher.Del(token)
@@ -300,17 +314,36 @@ func SetUserInfo(token string, authInfo *AuthInfo, duration time.Duration) {
api.Cacher.Set(token, authInfo, DefTokenDuration)
}
func ClearUserToken(userID string) {
if keys, err := api.Cacher.Keys(strings.Join([]string{
TokenHeader,
TokenVer,
userID,
"*",
}, TokenTypeSep)); err == nil {
for _, key := range keys {
api.Cacher.Del(key)
}
}
}
/////////////
func createToken(user IUser) (token string, tokenType int) {
userID := TokenUserEmpty
userName := TokenUserEmpty
tokenType = TokenTypeOnlyAuth
if user != nil {
userID = "[" + user.GetID2() + "]"
userID = user.GetID()
userName = "[" + user.GetID2() + "]"
tokenType = TokenTypeNormal
}
return strings.Join([]string{
TokenHeader,
TokenVer,
time.Now().Format("20060102-150405"),
userID,
time.Now().Format("20060102-150405"),
userName,
utils.GetUUID(),
}, TokenTypeSep), tokenType
}
@@ -319,7 +352,7 @@ func GetTokenType(token string) (tokenType int) {
tokenType = TokenTypeNone
if token != "" {
tokenPartList := strings.Split(token, TokenTypeSep)
if (len(tokenPartList) == 1) || (len(tokenPartList) == 4 && tokenPartList[2] != TokenUserEmpty) {
if (len(tokenPartList) == 1) || (len(tokenPartList) == 6 && tokenPartList[2] != TokenUserEmpty) {
tokenType = TokenTypeNormal
} else {
tokenType = TokenTypeOnlyAuth
@@ -344,3 +377,14 @@ func GuessAuthTypeFromAuthID(authID string) (authType string) {
}
return AuthTypeNone
}
func DisableUser(userID, operatorUserName string) (err error) {
if _, err = dao.UpdateEntityLogically(dao.GetDB(), &model.AuthBind{}, map[string]interface{}{
"Status": model.AuthBindStatusDisabled,
}, operatorUserName, map[string]interface{}{
"UserID": userID,
}); err == nil {
ClearUserToken(userID)
}
return err
}

View File

@@ -3,12 +3,15 @@ package cms
import (
"errors"
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
"git.rosy.net.cn/baseapi/utils"
"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/jxutils/jxcontext"
"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"
)
var (
@@ -111,3 +114,37 @@ func CreateUser(user *model.User) (err error) {
user.Status = model.UserStatusNormal
return dao.CreateEntity(nil, user)
}
func DisableUser(ctx *jxcontext.Context, userID string) (err error) {
userName := ctx.GetUserName()
if _, err = dao.UpdateEntityLogically(dao.GetDB(), &model.User{}, map[string]interface{}{
"Status": model.UserStatusDisabled,
}, userName, map[string]interface{}{
"UserID": userID,
}); err == nil {
auth2.DisableUser(userID, userName)
}
return err
}
func OnDingDingMsg(msg map[string]interface{}) (callbackResponse *dingdingapi.CallbackResponse) {
eventType := utils.Interface2String(msg[dingdingapi.KeyEventType])
if eventType == dingdingapi.CBTagUserLeaveOrg {
var (
authBind *model.AuthBind
err error
)
db := dao.GetDB()
for _, userID := range msg[dingdingapi.KeyUserID].([]interface{}) {
userIDStr := utils.Interface2String(userID)
globals.SugarLogger.Debugf("OnDingDingMsg dingding user:%s left company", userIDStr)
if authBind, err = dao.GetAuthBind(db, "", dingding.AuthTypeStaff, userIDStr); err == nil { // 直接找到了
globals.SugarLogger.Debugf("OnDingDingMsg dingding user:%s, userID:%s left company", userIDStr, authBind.UserID)
if err = DisableUser(jxcontext.AdminCtx, authBind.UserID); err != nil {
globals.SugarLogger.Errorf("OnDingDingMsg failed with error:%v", err)
}
}
}
}
return api.DingDingAPI.Err2CallbackResponse(nil)
}

View File

@@ -15,10 +15,11 @@ func GetAuthBind(db *DaoDB, userID, authType, authID string) (authBind *model.Au
sql := `
SELECT *
FROM auth_bind t1
WHERE t1.deleted_at = ?
WHERE t1.deleted_at = ? AND t1.status = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
model.AuthBindStatusNormal,
}
if userID != "" {
sql += " AND t1.user_id = ?"
@@ -41,9 +42,10 @@ func GetAuthBindsByAuthID2(db *DaoDB, authID2 string, typeList []string) (authBi
sql := `
SELECT *
FROM auth_bind t1
WHERE t1.deleted_at = ? AND t1.auth_id2 = ? AND t1.type IN (` + GenQuestionMarks(len(typeList)) + ")"
WHERE t1.deleted_at = ? AND t1.status = ? AND t1.auth_id2 = ? AND t1.type IN (` + GenQuestionMarks(len(typeList)) + ")"
sqlParams := []interface{}{
utils.DefaultTimeValue,
model.AuthBindStatusNormal,
authID2,
typeList,
}

View File

@@ -12,10 +12,11 @@ func GetUserByID(db *DaoDB, fieldName, fieldValue string) (user *model.User, err
sql := fmt.Sprintf(`
SELECT *
FROM user t1
WHERE t1.deleted_at = ? AND t1.%s = ?
WHERE t1.deleted_at = ? AND t1.status = ? AND t1.%s = ?
`, fieldName)
sqlParams := []interface{}{
utils.DefaultTimeValue,
model.UserStatusNormal,
fieldValue,
}
globals.SugarLogger.Debugf("GetUserByID sql:%s, sqlParams:%s", sql, utils.Format4Output(sqlParams, false))
@@ -27,8 +28,13 @@ func GetUserBindAuthInfo(db *DaoDB, userID string) (authList []*model.AuthBind,
sql := `
SELECT *
FROM auth_bind t1
WHERE t1.deleted_at = ? AND t1.user_id = ?
WHERE t1.deleted_at = ? AND t1.status = ? AND t1.user_id = ?
`
err = GetRows(db, &authList, sql, utils.DefaultTimeValue, userID)
sqlParams := []interface{}{
utils.DefaultTimeValue,
model.UserStatusNormal,
userID,
}
err = GetRows(db, &authList, sql, sqlParams...)
return authList, err
}

View File

@@ -4,6 +4,7 @@ import (
"net/http"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
"github.com/astaxie/beego"
@@ -24,8 +25,11 @@ func (c *DingDingController) Msg() {
obj, callbackResponse := api.DingDingAPI.GetCallbackMsg(dataMap, c.Ctx.Input.RequestBody)
if callbackResponse == nil {
globals.SugarLogger.Debugf("dingding msg, obj:%s", utils.Format4Output(obj, false))
callbackResponse = cms.OnDingDingMsg(dataMap)
if callbackResponse == nil {
callbackResponse = api.DingDingAPI.Err2CallbackResponse(nil)
}
}
c.Data["json"] = callbackResponse
c.ServeJSON()
} else {

View File

@@ -102,11 +102,14 @@ func main() {
orderman.LoadPendingOrders()
// 延时的原因是等回调准备好
if true { // beego.BConfig.RunMode == "prod" {
time.AfterFunc(2*time.Second, func() {
api.DingDingAPI.DeleteCallback()
if err := api.DingDingAPI.RegisterCallback([]string{dingdingapi.CBTagUserAddOrg, dingdingapi.CBTagUserModifyOrg, dingdingapi.CBTagUserLeaveOrg}, beego.AppConfig.DefaultString("dingdingCallbackToken", ""), beego.AppConfig.DefaultString("dingdingCallbackAESKey", ""), beego.AppConfig.DefaultString("dingdingCallbackURL", "")); err != nil {
globals.SugarLogger.Warnf("dingding RegisterCallback failed with error:%v", err)
}
})
}
if beego.BConfig.RunMode != "prod" {
beego.BConfig.WebConfig.DirectoryIndex = true