package controllers import ( "encoding/json" "fmt" "strconv" "time" "SSO/enums" "SSO/models" "SSO/service" "SSO/utils" ) type VerifyTokenController struct { BaseController } func (this *VerifyTokenController) Prepare() { this.EnableXSRF = false } // /verifytoken [post] // @param token:string // @param app_type:int // @param ip:string // @param session_id:string 客户端(浏览器)sessionID // return 说明:所有数值型的 key 和 value 都转换为了 string 类型 func (this *VerifyTokenController) VerifyToken() { token := this.GetString("token") clientSessionId := this.GetString("session_id") app_type, _ := this.GetInt("app_type", 0) // if app_type != 1 && app_type != 3 && app_type != 5 { // this.Data["json"] = enums.MakeFailResponseJSONWithSGJErrorCode(enums.ErrorCodeParamWrong) // this.ServeJSON() // return // } if url := service.GetAppURLWithAppType(app_type); len(url) == 0 { this.Data["json"] = enums.MakeFailResponseJSONWithSGJErrorCode(enums.ErrorCodeParamWrong) this.ServeJSON() return } utils.TraceLog("clientSessionId: %v", clientSessionId) if len(clientSessionId) == 0 { this.Data["json"] = enums.MakeFailResponseJSONWithSGJErrorCode(enums.ErrorCodeParamWrong) this.ServeJSON() return } if len(token) <= 24 { this.Data["json"] = enums.MakeFailResponseJSONWithSGJErrorCode(enums.ErrorCodeInvalidToken) this.ServeJSON() return } redisClient := service.RedisClient() defer redisClient.Close() mobile := token[24:] // locToken, _ := redisClient.Get(fmt.Sprintf("sso_token_%v", mobile)).Result() locToken, _ := redisClient.Get(fmt.Sprintf("sso_token_%v", clientSessionId)).Result() utils.TraceLog("request token: %v \t server cached token: %v", token, locToken) var isUserInfoFromRedis bool = false if token == locToken { infoStr, getCachedInfoErr := redisClient.Get("sso_admin_user_info_" + mobile).Result() if getCachedInfoErr != nil { utils.WarningLog("redis 获取管理员用户信息失败:%v", getCachedInfoErr) infoStr = "" } infoStr = "" var userInfo map[string]interface{} if len(infoStr) == 0 { utils.TraceLog("%v data is from operation", "sso_admin_user_info_"+mobile) isUserInfoFromRedis = false info, getInfoErr := this.GetAdminUserAllInfo(mobile) if getInfoErr != nil { this.Data["json"] = enums.MakeFailResponseJSONWithSGJError(getInfoErr) this.ServeJSON() return } userInfo = info infoStr_b, _ := json.Marshal(userInfo) redisClient.Set("sso_admin_user_info_"+mobile, string(infoStr_b), time.Duration(2)*time.Minute) } else { utils.TraceLog("%v data is from redis cache", "sso_admin_user_info_"+mobile) isUserInfoFromRedis = true userInfo = make(map[string]interface{}) json.Unmarshal([]byte(infoStr), &userInfo) } var adminUser models.AdminUser json.Unmarshal([]byte(userInfo["admin_user"].(string)), &adminUser) // 如果有登录记录,取出最近登录记录中的机构和应用 lastLoginLog, getLastLoginLogErr := service.GetAdminUserLastLoginLog(adminUser.Id, app_type) if getLastLoginLogErr != nil { utils.ErrorLog("数据错误:查找mobile = %v的用户最近一次登录记录时错误:%v", mobile, getLastLoginLogErr) } currentOrgId := 0 currentAppId := 0 if lastLoginLog != nil { currentOrgId = lastLoginLog.OrgId currentAppId = lastLoginLog.AppId } else { if isUserInfoFromRedis { orgIds := userInfo["org_ids"].([]interface{}) for _, oid := range orgIds { orgApps := userInfo["org_apps"].(map[string]interface{})[oid.(string)] for _, appMapJSON := range orgApps.(map[string]interface{}) { var appMap map[string]interface{} json.Unmarshal([]byte(appMapJSON.(string)), &appMap) a_t := int(appMap["app_type"].(float64)) if a_t == app_type { currentOrgId = int(appMap["org_id"].(float64)) currentAppId = int(appMap["id"].(float64)) break } } if currentOrgId != 0 && currentAppId != 0 { break } } } else { orgIds := userInfo["org_ids"].([]string) for _, oid := range orgIds { orgApps := userInfo["org_apps"].(map[string]interface{})[oid] for _, appMapJSON := range orgApps.(map[string]string) { var appMap map[string]interface{} json.Unmarshal([]byte(appMapJSON), &appMap) a_t := int(appMap["app_type"].(float64)) if a_t == app_type { currentOrgId = int(appMap["org_id"].(float64)) currentAppId = int(appMap["id"].(float64)) break } } if currentOrgId != 0 && currentAppId != 0 { break } } } } // for key, value := range userInfo { // if key == "purviews" || key == "purview_urlfors" { // continue // } // utils.TraceLog("%v: %v", key, value) // } utils.TraceLog("lastLoginLog : %v", lastLoginLog) utils.TraceLog("currentOrgId : %v", currentOrgId) utils.TraceLog("currentAppId : %v", currentAppId) if currentOrgId == 0 || currentAppId == 0 { if adminUser.IsSuperAdmin == true { this.Data["json"] = enums.MakeFailResponseJSONWithSGJErrorCode(enums.ErrorCodeNeverCreateTypeApp) this.ServeJSON() } else { this.Data["json"] = enums.MakeFailResponseJSONWithSGJErrorCode(enums.ErrorCodeContactSuperAdminCreateTypeApp) this.ServeJSON() } return } returnJSON := make(map[string]interface{}) returnJSON["admin_user"] = userInfo["admin_user"] returnJSON["org_ids"] = userInfo["org_ids"] returnJSON["orgs"] = userInfo["orgs"] returnJSON["org_app_ids"] = userInfo["org_app_ids"] returnJSON["org_apps"] = userInfo["org_apps"] returnJSON["app_to_org_ids"] = userInfo["app_to_org_ids"] returnJSON["current_org_id"] = strconv.Itoa(currentOrgId) returnJSON["current_app_id"] = strconv.Itoa(currentAppId) returnJSON["purviews"] = userInfo["purviews"] returnJSON["purview_urlfors"] = userInfo["purview_urlfors"] returnJSON["app_roles"] = userInfo["app_roles"] returnJSON["org_subscibes"] = userInfo["org_subscibes"] this.Data["json"] = enums.MakeSuccessResponseJSON(returnJSON) this.ServeJSON() // 插入一条登录记录 ip := this.GetString("ip") loginLog := &models.AdminUserLoginLog{ AdminUserId: adminUser.Id, OrgId: currentOrgId, AppId: currentAppId, IP: ip, OperateType: 1, AppType: int8(app_type), CreateTime: time.Now().Unix(), } if insertErr := service.InsertLoginLog(loginLog); insertErr != nil { utils.ErrorLog("为手机号为%v的用户插入一条登录记录失败:%v", mobile, insertErr) } } else { this.Data["json"] = enums.MakeFailResponseJSONWithSGJErrorCode(enums.ErrorCodeInvalidToken) this.ServeJSON() } } // 验证 token 之后需要返回的管理员用户的所有信息,包括:基本用户信息,所属的所有机构,机构下的所有应用 // map 的数据格式为 /* "admin_user": { AdminUser's json }, "org_ids": [1, 2, 3], "orgs": { (org_id: Org_Obj) 1: { Org's json }, 2: { Org's json }, }, "org_app_ids": { (org_id: org_app_ids) 1: [11, 12, 13], 2: [21, 22, 23], }, "org_apps": { (org_id: {app_id: OrgApp_Obj}) 1: { 11: { OrgApp's json }, 12: { OrgApp's json }, }, 2: { 21: { OrgApp's json }, 22: { OrgApp's json }, }, }, "app_to_org_ids": { (app_id: org_id) 11: 1, 12: 1, 21: 2, 22: 2, }, "app_roles": { (app_id: App_Role Obj) 11: {App_Role's json}, 12: {App_Role's json}, 21: {App_Role's json}, }, "purviews": { (app_id: [processed Purviews' json]) 11: [ {Purview's json .childs[ {Purview's json}, {Purview's json}, ]}, {Purview's json}, ], 12: [ {Purview's json}, {Purview's json}, ], } "purview_urlfors": { (app_id: [url_for]) 11: [ "Controller1.Action1", "Controller1.Action2", "Controller2.Action1", "Controller2.Action2", ], } 应当注意的是,屈服于 Golang 令人恶心的类型机制,这里将所有数值型的 key 或 value 全部转成了 string */ func (this *VerifyTokenController) GetAdminUserAllInfo(mobile string) (map[string]interface{}, *enums.SGJError) { adminUser := service.GetAdminUserWithMobile(mobile) if adminUser == nil { utils.ErrorLog("数据错误:查找不到mobile = %v的用户", mobile) return nil, &enums.SGJError{Code: enums.ErrorCodeDataException} } orgs, getOrgErr := service.GetAdminUserAllOrgWithUID(adminUser.Id, adminUser.IsSuperAdmin) if getOrgErr != nil { utils.ErrorLog("数据错误:查找不到mobile = %v的用户所属的机构:%v", mobile, getOrgErr) return nil, &enums.SGJError{Code: enums.ErrorCodeDataException} } if len(orgs) == 0 { utils.ErrorLog("数据错误:查找不到mobile = %v的用户所属的机构", mobile) return nil, &enums.SGJError{Code: enums.ErrorCodeDataException} } orgIds := make([]string, 0, len(orgs)) orgJSONs := make(map[string]string) orgAppIds := make(map[string]interface{}) orgApps := make(map[string]interface{}) app_to_org_ids := make(map[string]string) app_purviewJSONs := make(map[string]string) app_purview_urls := make(map[string]string) app_roles := make(map[string]string) org_subscibes := make(map[string]string) for _, org := range orgs { apps, getAppsErr := service.GetAdminUserAllOrgApp(adminUser.Id, org.Id) if getAppsErr != nil { utils.ErrorLog("数据错误:查找mobile = %v的用户所属机构ID为%v下的应用时错误:%v", mobile, org.Id, getAppsErr) return nil, &enums.SGJError{Code: enums.ErrorCodeDataException} } if adminUser.IsSuperAdmin { didCreateNewApp, createAppErr := this._createAppIfNeeded(adminUser.Id, org.Id, apps) if createAppErr != nil { return nil, createAppErr } if didCreateNewApp { apps, getAppsErr = service.GetAdminUserAllOrgApp(adminUser.Id, org.Id) if getAppsErr != nil { utils.ErrorLog("数据错误:查找mobile = %v的用户所属机构ID为%v下的应用时错误:%v", mobile, org.Id, getAppsErr) return nil, &enums.SGJError{Code: enums.ErrorCodeDataException} } } } else { if len(apps) == 0 { continue } } subscibe, getSubscibeErr := service.GetOrgServeSubscibe(org.Id) if getSubscibeErr != nil { utils.ErrorLog("获取机构订阅信息失败:%v", getSubscibeErr) return nil, &enums.SGJError{Code: enums.ErrorCodeDataException} } else if subscibe == nil { now := time.Now() nextMonthDate := now.AddDate(0, 0, 30) subscibe = &models.ServeSubscibe{ OrgId: int64(org.Id), PeriodStart: now.Unix(), PeriodEnd: nextMonthDate.Unix(), Status: 1, CreatedTime: now.Unix(), UpdatedTime: now.Unix(), State: 2, } createErr := service.CreateOrgServeSubscibe(subscibe) if createErr != nil { utils.ErrorLog(" 创建机构订阅信息失败:%v", createErr) return nil, &enums.SGJError{Code: enums.ErrorCodeDataException} } } subscibeJSON_b, _ := json.Marshal(subscibe) subscibeJSON := string(subscibeJSON_b) org_subscibes[strconv.Itoa(org.Id)] = subscibeJSON orgJSON_b, _ := json.Marshal(org) orgJSONStr := string(orgJSON_b) orgJSONs[strconv.Itoa(org.Id)] = orgJSONStr orgIds = append(orgIds, strconv.Itoa(org.Id)) appIds := make([]string, 0, len(apps)) appJSONs := make(map[string]string) for _, app := range apps { appJSON_b, _ := json.Marshal(app) appJSONStr := string(appJSON_b) appJSONs[strconv.Itoa(app.Id)] = appJSONStr appIds = append(appIds, strconv.Itoa(app.Id)) app_to_org_ids[strconv.Itoa(app.Id)] = strconv.Itoa(org.Id) if adminUser.IsSuperAdmin { urlfors, purviews, getPurviewErr := service.GetSuperAdminUsersPurviewTreeAndUrlfors(app.AppType) if getPurviewErr != nil { utils.ErrorLog("数据错误:查找超级管理员的类型为%v的应用的权限时错误:%v", app.AppType, getPurviewErr) return nil, &enums.SGJError{Code: enums.ErrorCodeDataException} } else { purviewJSONs_b, _ := json.Marshal(purviews) app_purviewJSONs[strconv.Itoa(app.Id)] = string(purviewJSONs_b) urlforJSON_b, _ := json.Marshal(urlfors) app_purview_urls[strconv.Itoa(app.Id)] = string(urlforJSON_b) } } else { urlfors, purviews, getPurviewErr := service.GetGeneralAdminUsersPurviewTreeAndUrlfors(adminUser.Id, app.Id) if getPurviewErr != nil { utils.ErrorLog("数据错误:查找id为%v普通管理员的id为%v的应用的权限时错误:%v", adminUser.Id, app.Id, getPurviewErr) return nil, &enums.SGJError{Code: enums.ErrorCodeDataException} } else { purviewJSONs_b, _ := json.Marshal(purviews) app_purviewJSONs[strconv.Itoa(app.Id)] = string(purviewJSONs_b) urlforJSON_b, _ := json.Marshal(urlfors) app_purview_urls[strconv.Itoa(app.Id)] = string(urlforJSON_b) } } appRole, getAppRoleErr := service.GetAppRole(adminUser.Id, org.Id, app.Id) if getAppRoleErr != nil { utils.ErrorLog("数据错误:查找id=%v,orgid=%v,appid=%v的用户信息时失败:%v", adminUser.Id, org.Id, app.Id, getAppRoleErr) return nil, &enums.SGJError{Code: enums.ErrorCodeDataException} } appRoleJSON_b, _ := json.Marshal(appRole) app_roles[strconv.Itoa(app.Id)] = string(appRoleJSON_b) } orgAppIds[strconv.Itoa(org.Id)] = appIds orgApps[strconv.Itoa(org.Id)] = appJSONs } adminUserJSON_b, _ := json.Marshal(adminUser) info := make(map[string]interface{}) info["admin_user"] = string(adminUserJSON_b) info["org_ids"] = orgIds info["orgs"] = orgJSONs info["org_app_ids"] = orgAppIds info["org_apps"] = orgApps info["app_to_org_ids"] = app_to_org_ids info["app_roles"] = app_roles info["purviews"] = app_purviewJSONs info["purview_urlfors"] = app_purview_urls info["org_subscibes"] = org_subscibes return info, nil } func (this *VerifyTokenController) _createAppIfNeeded(adminUserID int, orgID int, didCreatedApps []*models.OrgApp) (bool, *enums.SGJError) { // 已创建的应用的信息 did_patient_manage_create := false did_dialysis_manage_create := false did_cdm_manage_create := false did_mall_manage_create := false for _, app := range didCreatedApps { if app.AppType == 1 { did_patient_manage_create = true } else if app.AppType == 3 { did_dialysis_manage_create = true } else if app.AppType == 4 { did_cdm_manage_create = true } else if app.AppType == 5 { did_mall_manage_create = true } } // 自动创建所有应用 didCreateNew := false if did_dialysis_manage_create == false { err := service.CreateOrgApp(adminUserID, orgID, 3, false) if err != nil { utils.ErrorLog("自动创建透析管理应用失败:%v", err) return false, &enums.SGJError{Code: enums.ErrorCodeDataException} } didCreateNew = true } if did_cdm_manage_create == false { err := service.CreateOrgApp(adminUserID, orgID, 4, false) if err != nil { utils.ErrorLog("自动创建慢病管理应用失败:%v", err) return false, &enums.SGJError{Code: enums.ErrorCodeDataException} } didCreateNew = true } if did_patient_manage_create == false { err := service.CreateOrgApp(adminUserID, orgID, 1, false) if err != nil { utils.ErrorLog("自动创建酷医聚客应用失败:%v", err) return false, &enums.SGJError{Code: enums.ErrorCodeDataException} } didCreateNew = true } if did_mall_manage_create == false { err := service.CreateOrgApp(adminUserID, orgID, 5, false) if err != nil { utils.ErrorLog("自动创建微商城应用失败:%v", err) return false, &enums.SGJError{Code: enums.ErrorCodeDataException} } didCreateNew = true } return didCreateNew, nil }