- v2 token format changed
- DisableUser - clear all tokens when disable user - handle ding ding user leave event
This commit is contained in:
@@ -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 // 正式TOKEN,7天有效期
|
||||
TmpTokenDuration = 30 * time.Minute // 临时TOKEN,30分钟有效期
|
||||
MinCaptchaLen = 4
|
||||
MaxCaptchaWidth = 400
|
||||
MaxCaptchaHeight = 400
|
||||
)
|
||||
|
||||
type IUser interface {
|
||||
@@ -113,21 +118,23 @@ 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,
|
||||
TokenType: tokenType,
|
||||
LoginTime: time.Now(),
|
||||
ExpiresIn: time.Now().Add(DefTokenDuration).Unix(),
|
||||
Token: token,
|
||||
TokenType: tokenType,
|
||||
}
|
||||
if user != nil {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,7 +25,10 @@ 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 = api.DingDingAPI.Err2CallbackResponse(nil)
|
||||
callbackResponse = cms.OnDingDingMsg(dataMap)
|
||||
if callbackResponse == nil {
|
||||
callbackResponse = api.DingDingAPI.Err2CallbackResponse(nil)
|
||||
}
|
||||
}
|
||||
c.Data["json"] = callbackResponse
|
||||
c.ServeJSON()
|
||||
|
||||
13
main.go
13
main.go
@@ -102,11 +102,14 @@ func main() {
|
||||
orderman.LoadPendingOrders()
|
||||
|
||||
// 延时的原因是等回调准备好
|
||||
time.AfterFunc(2*time.Second, func() {
|
||||
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 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
|
||||
|
||||
Reference in New Issue
Block a user