package security import ( "encoding/json" "fmt" "io" "net/http" "strconv" "strings" "time" "ems.agt/features/security/service" sysConfigService "ems.agt/features/sys_config/service" "ems.agt/lib/core/account" "ems.agt/lib/core/cache" "ems.agt/lib/core/constants/cachekey" "ems.agt/lib/core/utils/ctx" "ems.agt/lib/core/vo/result" "ems.agt/lib/dborm" "ems.agt/lib/global" "ems.agt/lib/log" "ems.agt/lib/oauth" "ems.agt/lib/services" "ems.agt/restagent/config" srcConfig "ems.agt/src/framework/config" "ems.agt/src/framework/redis" ) var ( UriOauthToken = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/token" UriOauthHandshake = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/handshake" CustomUriOauthToken = config.UriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/token" CustomUriOauthHandshake = config.UriPrefix + "/securityManagement/{apiVersion}/{elementTypeValue}/handshake" // 系统登录 UriLogin = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/login" CustomUriLogin = config.UriPrefix + "/securityManagement/{apiVersion}/login" // 获取验证码 UriCaptchaImage = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/captchaImage" CustomUriCaptchaImage = config.UriPrefix + "/securityManagement/{apiVersion}/captchaImage" // 登录用户信息 UriUserInfo = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/getUserInfo" CustomUriUserInfo = config.UriPrefix + "/securityManagement/{apiVersion}/getUserInfo" // 登录用户路由信息 UriRouters = config.DefaultUriPrefix + "/securityManagement/{apiVersion}/getRouters" CustomUriRouters = config.UriPrefix + "/securityManagement/{apiVersion}/getRouters" ) func LoginFromOMC(w http.ResponseWriter, r *http.Request) { log.Info("LoginFromOMC processing... ") body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen)) //io.LimitReader限制大小 if err != nil { log.Error("Failed to ReadAll:", err) services.ResponseNotFound404UriNotExist(w, r) return } // check media type(content type) only support "application/json" if !services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) { log.Debug("Invalid Content-Type") services.ResponseUnsupportedMediaType415(w) return } // // check extend uri, response 404 // if !IsValidOAuthUri(r) { // log.Debug("Uri is invalid") // services.ResponseNotFound404UriNotExist(w, r) // return // } // Error process .... // response 400-7 if !json.Valid([]byte(body)) { log.Error("Invalid Json Format") services.ResponseBadRequest400InvalidJson(w) return } var oAuthBody oauth.OAuthBody _ = json.Unmarshal(body, &oAuthBody) //转为json //log.Debug("body:", string(body), "oAuthBody:", oAuthBody) defer r.Body.Close() // response 400-5 if oauth.IsWrongOAuthInfo(oAuthBody) { log.Error("Wrong parameter value") services.ResponseBadRequest400WrongParamValue(w) return } /* if oauth.IsValidOAuthInfo(oAuthBody) { plist := config.GetPermissionFromConfig(oAuthBody.UserName, oAuthBody.GrantType) log.Debug("Permission list:", plist) token := globalSession.NewSession(w, r, plist) services.ResponseStatusOK200Login(w, token) } else { // response 400-4 log.Debug("Authentication failed, mismatch user or password") services.ResponseBadRequest400IncorrectLogin(w) } */ validUser, user, err := dborm.XormCheckLoginUser(oAuthBody.UserName, oAuthBody.Value, config.GetYamlConfig().Auth.Crypt) if !validUser || err != nil { // response 400-4 log.Error("Authentication failed, mismatch user or password") services.ResponseErrorWithJson(w, 400, err.Error()) return } token := oauth.GenRandToken("omc") // Generate new token to session ID sourceAddr := r.RemoteAddr[:strings.Index(r.RemoteAddr, ":")] affected, err := dborm.XormInsertSession(oAuthBody.UserName, sourceAddr, token, config.GetExpiresFromConfig(), config.GetYamlConfig().Auth.Session) if err != nil { log.Error("Failed to XormInsertSession:", err) if affected == -1 { services.ResponseForbidden403MultiLoginNotAllowed(w) } else { services.ResponseBadRequest400IncorrectLogin(w) } return } if user != nil { // 缓存用户信息 account.CacheLoginUser(user) redis.SetByExpire("", "session_token", token, time.Second*1800) // 角色权限集合,管理员拥有所有权限 userId := fmt.Sprint(user.Id) isAdmin := srcConfig.IsAdmin(userId) roles, perms := service.NewServiceAccount.RoleAndMenuPerms(userId, isAdmin) services.ResponseStatusOK200LoginWhitRP(w, token, user, roles, perms) return } services.ResponseBadRequest400IncorrectLogin(w) } func LogoutFromOMC(w http.ResponseWriter, r *http.Request) { log.Info("LogoutFromOMC processing... ") token, err := services.CheckFrontValidRequest(w, r) if err != nil { log.Error("Request error:", err) return } // // check media type(content type) only support "application/json" // if services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) == false { // log.Error("Invalid Content-Type") // services.ResponseUnsupportedMediaType415(w) // return // } // // check extend uri, response 404 // if !services.IsValidOAuthUri(r) { // log.Error("Uri is invalid") // services.ResponseNotFound404UriNotExist(w, r) // return // } // // error processing ... // // 401-1 response // token, ret := oauth.IsCarriedToken(r) // if ret == false { // log.Error("AccessToken is not carried") // services.ResponseUnauthorized401AccessTokenNotCarried(w) // return // } se, err := dborm.XormLogoutUpdateSession(token) if err != nil { log.Error("Uri is invalid") services.ResponseNotFound404UriNotExist(w, r) return } // 清除缓存用户信息 account.ClearLoginUser(se.AccountId) services.ResponseStatusOK200Null(w) } func HandshakeFromOMC(w http.ResponseWriter, r *http.Request) { log.Info("HandshakeFromOMC processing... ") // check media type(content type) only support "application/json" if !services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) { log.Debug("Invalid Content-Type") services.ResponseUnsupportedMediaType415(w) return } // check extend uri, response 404 if !services.IsValidOAuthUri(r) { log.Error("Uri is invalid") services.ResponseNotFound404UriNotExist(w, r) return } // error processing ... // 401-1 response token, ret := oauth.IsCarriedToken(r) if !ret { log.Error("AccessToken is not carried") services.ResponseUnauthorized401AccessTokenNotCarried(w) return } _, err := dborm.XormUpdateSessionShakeTime(token) if err != nil { log.Error("Uri is invalid") services.ResponseNotFound404UriNotExist(w, r) return } services.ResponseStatusOK200Null(w) } // 系统登录 // // POST /login func LoginOMC(w http.ResponseWriter, r *http.Request) { log.Info("LoginOMC processing... ") var body struct { Username string `json:"username" binding:"required"` // Username 用户名 Password string `json:"password" binding:"required"` // Password 用户密码 Code string `json:"code"` // Code 验证码 UUID string `json:"uuid"` // UUID 验证码唯一标识 } err := ctx.ShouldBindJSON(r, &body) if err != nil { log.Error("Invalid Json Format") ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) return } // response 400-5 if body.Username == "" || body.Password == "" { log.Error("Wrong parameter value") ctx.JSON(w, 400, result.CodeMsg(400, "parameter error")) return } // 校验验证码 // 从数据库配置获取验证码开关 true开启,false关闭 captchaEnabledStr := sysConfigService.NewServiceSysConfig.SelectConfigValueByKey("sys.account.captchaEnabled") captchaEnabled, err := strconv.ParseBool(captchaEnabledStr) if err != nil { captchaEnabled = false } if captchaEnabled { if body.Code == "" || body.UUID == "" { log.Error("Authentication failed, mismatch captcha") ctx.JSON(w, 400, result.CodeMsg(400, "Verification code information error")) return } verifyKey := cachekey.CAPTCHA_CODE_KEY + body.UUID captcha, ok := cache.GetLocalTTL(verifyKey) if captcha == nil || !ok { log.Error("Authentication failed, captcha emtry") ctx.JSON(w, 400, result.CodeMsg(400, "The verification code has expired")) return } cache.DeleteLocalTTL(verifyKey) if captcha.(string) != body.Code { log.Error("Authentication failed, not match captcha") ctx.JSON(w, 400, result.CodeMsg(400, "Verification code error")) return } } validUser, user, err := dborm.XormCheckLoginUser(body.Username, body.Password, config.GetYamlConfig().Auth.Crypt) if !validUser || err != nil { // response 400-4 log.Error("Authentication failed, mismatch user or password") ctx.JSON(w, 400, result.CodeMsg(400, err.Error())) return } token := oauth.GenRandToken("omc") // Generate new token to session ID sourceAddr := r.RemoteAddr[:strings.Index(r.RemoteAddr, ":")] affected, err := dborm.XormInsertSession(body.Username, sourceAddr, token, config.GetExpiresFromConfig(), config.GetYamlConfig().Auth.Session) if err != nil { log.Error("Failed to XormInsertSession:", err) if affected == -1 { services.ResponseForbidden403MultiLoginNotAllowed(w) } else { services.ResponseBadRequest400IncorrectLogin(w) } return } if user != nil { // 缓存用户信息 account.CacheLoginUser(user) redis.SetByExpire("", "session_token", token, time.Second*1800) ctx.JSON(w, 200, result.OkData(map[string]any{ "accessToken": token, })) return } ctx.JSON(w, 200, result.Err(nil)) }