- 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/baseapi/utils"
|
||||||
"git.rosy.net.cn/jx-callback/business/model"
|
"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"
|
||||||
"git.rosy.net.cn/jx-callback/globals/api"
|
"git.rosy.net.cn/jx-callback/globals/api"
|
||||||
"github.com/dchest/captcha"
|
"github.com/dchest/captcha"
|
||||||
@@ -24,6 +25,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
TokenHeader = "TOKEN"
|
||||||
TokenVer = "V2"
|
TokenVer = "V2"
|
||||||
TokenTypeSep = "."
|
TokenTypeSep = "."
|
||||||
TokenUserEmpty = "NULL"
|
TokenUserEmpty = "NULL"
|
||||||
@@ -37,8 +39,11 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DefTokenDuration = 7 * 24 * time.Hour // 7天
|
DefTokenDuration = 7 * 24 * time.Hour // 正式TOKEN,7天有效期
|
||||||
|
TmpTokenDuration = 30 * time.Minute // 临时TOKEN,30分钟有效期
|
||||||
MinCaptchaLen = 4
|
MinCaptchaLen = 4
|
||||||
|
MaxCaptchaWidth = 400
|
||||||
|
MaxCaptchaHeight = 400
|
||||||
)
|
)
|
||||||
|
|
||||||
type IUser interface {
|
type IUser interface {
|
||||||
@@ -113,21 +118,23 @@ func RegisterAuther(authType string, handler IAuther) {
|
|||||||
|
|
||||||
func createAuthInfo(user IUser, authBindInfo *AuthBindEx) (authInfo *AuthInfo) {
|
func createAuthInfo(user IUser, authBindInfo *AuthBindEx) (authInfo *AuthInfo) {
|
||||||
token, tokenType := createToken(user)
|
token, tokenType := createToken(user)
|
||||||
|
expireDuration := DefTokenDuration
|
||||||
authInfo = &AuthInfo{
|
authInfo = &AuthInfo{
|
||||||
AuthBindInfo: authBindInfo,
|
AuthBindInfo: authBindInfo,
|
||||||
|
LoginTime: time.Now(),
|
||||||
LoginTime: time.Now(),
|
ExpiresIn: time.Now().Add(DefTokenDuration).Unix(),
|
||||||
ExpiresIn: time.Now().Add(DefTokenDuration).Unix(),
|
Token: token,
|
||||||
Token: token,
|
TokenType: tokenType,
|
||||||
TokenType: tokenType,
|
|
||||||
}
|
}
|
||||||
if user != nil {
|
if user != nil {
|
||||||
authInfo.UpdateByIUser(user)
|
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))
|
globals.SugarLogger.Debugf("createAuthInfo id:%s, id2:%s, mobile:%s, authInfo:%s", authInfo.GetID(), authInfo.GetID2(), authInfo.GetMobile(), utils.Format4Output(authInfo, true))
|
||||||
} else {
|
} else {
|
||||||
|
expireDuration = TmpTokenDuration
|
||||||
|
authInfo.ExpiresIn = time.Now().Add(expireDuration).Unix()
|
||||||
globals.SugarLogger.Debugf("createAuthInfo authInfo:%s", utils.Format4Output(authInfo, true))
|
globals.SugarLogger.Debugf("createAuthInfo authInfo:%s", utils.Format4Output(authInfo, true))
|
||||||
}
|
}
|
||||||
SetUserInfo(token, authInfo, DefTokenDuration)
|
SetUserInfo(token, authInfo, expireDuration)
|
||||||
return authInfo
|
return authInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,6 +142,12 @@ func CreateCaptcha(width, height, captchaLen int) (captchaInfo *CaptchaInfo, err
|
|||||||
if captchaLen < MinCaptchaLen {
|
if captchaLen < MinCaptchaLen {
|
||||||
captchaLen = MinCaptchaLen
|
captchaLen = MinCaptchaLen
|
||||||
}
|
}
|
||||||
|
if width > MaxCaptchaWidth {
|
||||||
|
width = MaxCaptchaWidth
|
||||||
|
}
|
||||||
|
if height > MaxCaptchaHeight {
|
||||||
|
height = MaxCaptchaHeight
|
||||||
|
}
|
||||||
captchaInfo = &CaptchaInfo{
|
captchaInfo = &CaptchaInfo{
|
||||||
ID: captcha.NewLen(captchaLen),
|
ID: captcha.NewLen(captchaLen),
|
||||||
}
|
}
|
||||||
@@ -283,6 +296,7 @@ func Logout(authInfo *AuthInfo) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// token缓存相关
|
// token缓存相关
|
||||||
|
/////////////
|
||||||
|
|
||||||
func RemoveUserInfo(token string) {
|
func RemoveUserInfo(token string) {
|
||||||
api.Cacher.Del(token)
|
api.Cacher.Del(token)
|
||||||
@@ -300,17 +314,36 @@ func SetUserInfo(token string, authInfo *AuthInfo, duration time.Duration) {
|
|||||||
api.Cacher.Set(token, authInfo, DefTokenDuration)
|
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) {
|
func createToken(user IUser) (token string, tokenType int) {
|
||||||
userID := TokenUserEmpty
|
userID := TokenUserEmpty
|
||||||
|
userName := TokenUserEmpty
|
||||||
tokenType = TokenTypeOnlyAuth
|
tokenType = TokenTypeOnlyAuth
|
||||||
if user != nil {
|
if user != nil {
|
||||||
userID = "[" + user.GetID2() + "]"
|
userID = user.GetID()
|
||||||
|
userName = "[" + user.GetID2() + "]"
|
||||||
tokenType = TokenTypeNormal
|
tokenType = TokenTypeNormal
|
||||||
}
|
}
|
||||||
return strings.Join([]string{
|
return strings.Join([]string{
|
||||||
|
TokenHeader,
|
||||||
TokenVer,
|
TokenVer,
|
||||||
time.Now().Format("20060102-150405"),
|
|
||||||
userID,
|
userID,
|
||||||
|
time.Now().Format("20060102-150405"),
|
||||||
|
userName,
|
||||||
utils.GetUUID(),
|
utils.GetUUID(),
|
||||||
}, TokenTypeSep), tokenType
|
}, TokenTypeSep), tokenType
|
||||||
}
|
}
|
||||||
@@ -319,7 +352,7 @@ func GetTokenType(token string) (tokenType int) {
|
|||||||
tokenType = TokenTypeNone
|
tokenType = TokenTypeNone
|
||||||
if token != "" {
|
if token != "" {
|
||||||
tokenPartList := strings.Split(token, TokenTypeSep)
|
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
|
tokenType = TokenTypeNormal
|
||||||
} else {
|
} else {
|
||||||
tokenType = TokenTypeOnlyAuth
|
tokenType = TokenTypeOnlyAuth
|
||||||
@@ -344,3 +377,14 @@ func GuessAuthTypeFromAuthID(authID string) (authType string) {
|
|||||||
}
|
}
|
||||||
return AuthTypeNone
|
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 (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
|
||||||
"git.rosy.net.cn/baseapi/utils"
|
"git.rosy.net.cn/baseapi/utils"
|
||||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
"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/jxutils/jxcontext"
|
||||||
"git.rosy.net.cn/jx-callback/business/model"
|
"git.rosy.net.cn/jx-callback/business/model"
|
||||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||||
"git.rosy.net.cn/jx-callback/globals"
|
"git.rosy.net.cn/jx-callback/globals"
|
||||||
|
"git.rosy.net.cn/jx-callback/globals/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -111,3 +114,37 @@ func CreateUser(user *model.User) (err error) {
|
|||||||
user.Status = model.UserStatusNormal
|
user.Status = model.UserStatusNormal
|
||||||
return dao.CreateEntity(nil, user)
|
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 := `
|
sql := `
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM auth_bind t1
|
FROM auth_bind t1
|
||||||
WHERE t1.deleted_at = ?
|
WHERE t1.deleted_at = ? AND t1.status = ?
|
||||||
`
|
`
|
||||||
sqlParams := []interface{}{
|
sqlParams := []interface{}{
|
||||||
utils.DefaultTimeValue,
|
utils.DefaultTimeValue,
|
||||||
|
model.AuthBindStatusNormal,
|
||||||
}
|
}
|
||||||
if userID != "" {
|
if userID != "" {
|
||||||
sql += " AND t1.user_id = ?"
|
sql += " AND t1.user_id = ?"
|
||||||
@@ -41,9 +42,10 @@ func GetAuthBindsByAuthID2(db *DaoDB, authID2 string, typeList []string) (authBi
|
|||||||
sql := `
|
sql := `
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM auth_bind t1
|
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{}{
|
sqlParams := []interface{}{
|
||||||
utils.DefaultTimeValue,
|
utils.DefaultTimeValue,
|
||||||
|
model.AuthBindStatusNormal,
|
||||||
authID2,
|
authID2,
|
||||||
typeList,
|
typeList,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,11 @@ func GetUserByID(db *DaoDB, fieldName, fieldValue string) (user *model.User, err
|
|||||||
sql := fmt.Sprintf(`
|
sql := fmt.Sprintf(`
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM user t1
|
FROM user t1
|
||||||
WHERE t1.deleted_at = ? AND t1.%s = ?
|
WHERE t1.deleted_at = ? AND t1.status = ? AND t1.%s = ?
|
||||||
`, fieldName)
|
`, fieldName)
|
||||||
sqlParams := []interface{}{
|
sqlParams := []interface{}{
|
||||||
utils.DefaultTimeValue,
|
utils.DefaultTimeValue,
|
||||||
|
model.UserStatusNormal,
|
||||||
fieldValue,
|
fieldValue,
|
||||||
}
|
}
|
||||||
globals.SugarLogger.Debugf("GetUserByID sql:%s, sqlParams:%s", sql, utils.Format4Output(sqlParams, false))
|
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 := `
|
sql := `
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM auth_bind t1
|
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
|
return authList, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"git.rosy.net.cn/baseapi/utils"
|
"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"
|
||||||
"git.rosy.net.cn/jx-callback/globals/api"
|
"git.rosy.net.cn/jx-callback/globals/api"
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
@@ -24,7 +25,10 @@ func (c *DingDingController) Msg() {
|
|||||||
obj, callbackResponse := api.DingDingAPI.GetCallbackMsg(dataMap, c.Ctx.Input.RequestBody)
|
obj, callbackResponse := api.DingDingAPI.GetCallbackMsg(dataMap, c.Ctx.Input.RequestBody)
|
||||||
if callbackResponse == nil {
|
if callbackResponse == nil {
|
||||||
globals.SugarLogger.Debugf("dingding msg, obj:%s", utils.Format4Output(obj, false))
|
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.Data["json"] = callbackResponse
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
|
|||||||
13
main.go
13
main.go
@@ -102,11 +102,14 @@ func main() {
|
|||||||
orderman.LoadPendingOrders()
|
orderman.LoadPendingOrders()
|
||||||
|
|
||||||
// 延时的原因是等回调准备好
|
// 延时的原因是等回调准备好
|
||||||
time.AfterFunc(2*time.Second, func() {
|
if true { // beego.BConfig.RunMode == "prod" {
|
||||||
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 {
|
time.AfterFunc(2*time.Second, func() {
|
||||||
globals.SugarLogger.Warnf("dingding RegisterCallback failed with error:%v", err)
|
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" {
|
if beego.BConfig.RunMode != "prod" {
|
||||||
beego.BConfig.WebConfig.DirectoryIndex = true
|
beego.BConfig.WebConfig.DirectoryIndex = true
|
||||||
|
|||||||
Reference in New Issue
Block a user