12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520 |
- // Copyright 2019 utimes.cc. All rights reserved.
- // Use of this source code is governed by utimes.cc.
- // data_api_check 包提供平台api参数校验功能,和与业务相关的后台数据查询功能
- package data_api_check
- import (
- "context"
- "encoding/hex"
- "encoding/json"
- "fmt"
- "gd_auth_check/apis"
- "gd_auth_check/errors"
- "gd_auth_check/limit"
- "github.com/tidwall/gjson"
- "sort"
- "strconv"
- "strings"
- "sync"
- "time"
- "gd_auth_check/common.in/cache"
- "gd_auth_check/common.in/config"
- "gd_auth_check/common.in/jsonrpc2"
- "gd_auth_check/common.in/utils"
- "github.com/astaxie/beego/orm"
- "go.uber.org/zap"
- )
- // timeInfo 包含api用量、时间等信息
- type timeInfo struct {
- // mdaId 商户数据api id
- mdaId int64
- // startTime 套餐的开始时间
- startTime int64
- // endTime 套餐的结束时间
- endTime int64
- // dayCount 单天调用量上限
- dayCount int
- // totalCount 总调用量上限
- totalCount int
- // 套餐类型
- comboType int
- // 是否是免费套餐
- isFree int
- // 单天即查量上限
- dayTotalCount int
- }
- // checkTimeResult 包含用量检查后的信息
- type checkTimeResult struct {
- info timeInfo
- // accessCountId 对应的计数日志id
- accessCountId int64
- // 套餐类型
- comboType int
- // 剩余使用天数
- remainDays int
- // 剩余总次数
- remainCount int
- // 剩余单天次数
- remainDayCount int
- // 总的天数上限
- totalDays int
- }
- // setMysqlError 记录mysql错误信息
- func setMysqlError(sql string, args string, err error) {
- if err != nil {
- l.Error("mysql",
- zap.String("sql", sql),
- zap.String("args", args),
- zap.String("error", err.Error()))
- }
- }
- // redis 消息channel
- const (
- ApiNotifyChannel = "api_notify"
- MerchantNotifyChannel = "merchant_notify"
- MerchantApiNotifyChannel = "merchant_api_notify"
- )
- type ApiInfo struct {
- apiId int64
- apiName string
- enable bool
- }
- // 本地缓存map
- var apiMap = map[string]*ApiInfo{}
- var merchantMap = map[string]*MerchantInfo{}
- var merchantApiMap = map[string][]orm.Params{}
- //var priceMap = map[int64]float64{}
- // 操作本地缓存的锁
- var apiMutex sync.RWMutex
- var merchantMutex sync.RWMutex
- var merchantApiMutex sync.RWMutex
- var priceMutex sync.Mutex
- // setApiMap 设置基础api本地缓存
- func setApiMap(router, method string, apiId int64, apiName string, enable bool) {
- apiMutex.Lock()
- defer apiMutex.Unlock()
- key := router + "-" + method
- apiMap[key] = &ApiInfo{
- apiId: apiId,
- apiName: apiName,
- enable: enable,
- }
- }
- // getApiFromMap从本地缓存获取基础api信息
- func getApiFromMap(router, method string) *ApiInfo {
- apiMutex.RLock()
- defer apiMutex.RUnlock()
- key := router + "-" + method
- ret, ok := apiMap[key]
- if ok == false {
- return nil
- }
- return ret
- }
- // setMerchantMap 商户基本信息保存到本地缓存
- func setMerchantMap(appKey string, merchantInfo *MerchantInfo) {
- merchantMutex.Lock()
- defer merchantMutex.Unlock()
- merchantMap[appKey] = merchantInfo
- }
- // getMerchantFromMap 从本地缓存获取商户基本信息
- func getMerchantFromMap(appKey string) *MerchantInfo {
- merchantMutex.RLock()
- defer merchantMutex.RUnlock()
- ret, ok := merchantMap[appKey]
- if ok == false {
- return nil
- }
- return ret
- }
- // setMerchantApiMap 将商户的api信息保存到本地缓存
- func setMerchantApiMap(apiId int64, merchantId int64, infos []orm.Params) {
- merchantApiMutex.Lock()
- defer merchantApiMutex.Unlock()
- key := fmt.Sprintf("%d-%d", apiId, merchantId)
- merchantApiMap[key] = infos
- }
- // getMerchantApiFromMap 从本地缓存获取商户的api信息
- func getMerchantApiFromMap(apiId int64, merchantId int64) []orm.Params {
- merchantApiMutex.RLock()
- defer merchantApiMutex.RUnlock()
- key := fmt.Sprintf("%d-%d", apiId, merchantId)
- ret, ok := merchantApiMap[key]
- if ok == false {
- return nil
- }
- return ret
- }
- // cleanMerchantMap 清理本地缓存的商户信息
- func cleanMerchantMap() {
- merchantMutex.Lock()
- defer merchantMutex.Unlock()
- i := 0
- array := make([]string, len(merchantMap))
- for k, _ := range merchantMap {
- array[i] = k
- i++
- }
- for _, v := range array {
- delete(merchantMap, v)
- }
- }
- /*func cleanPriceMap(){
- priceMutex.Lock()
- defer priceMutex.Unlock()
- array := make([]int64, len(priceMap))
- i := 0
- for k, _ := range priceMap {
- array[i] = k
- i++
- }
- for _, v := range array {
- delete(priceMap, v)
- }
- }*/
- // cleanMerchantApiMap 清理本地缓存的商户api信息
- func cleanMerchantApiMap() {
- merchantApiMutex.Lock()
- defer merchantApiMutex.Unlock()
- i := 0
- array := make([]string, len(merchantApiMap))
- for k, _ := range merchantApiMap {
- array[i] = k
- i++
- }
- for _, v := range array {
- delete(merchantApiMap, v)
- }
- }
- // cleanApiMap清理本地缓存的基础api信息
- func cleanApiMap() {
- apiMutex.Lock()
- defer apiMutex.Unlock()
- i := 0
- array := make([]string, len(apiMap))
- for k, _ := range apiMap {
- array[i] = k
- i++
- }
- for _, v := range array {
- delete(apiMap, v)
- }
- }
- // CleanLocalCache 定时清理本地缓存
- func CleanLocalCache() {
- t := time.NewTicker(5 * time.Minute)
- for {
- select {
- case <-t.C:
- LoadRedis()
- cleanApiMap()
- cleanMerchantMap()
- cleanMerchantApiMap()
- //cleanPriceMap()
- }
- }
- }
- // clearApiMap 删除本地缓存的某个基础api
- func clearApiMap(router, method string) {
- apiMutex.Lock()
- defer apiMutex.Unlock()
- key := router + "-" + method
- delete(apiMap, key)
- }
- // clearMerchantMap 删除本地缓存的某个商户
- func clearMerchantMap(appKey string) {
- merchantMutex.Lock()
- defer merchantMutex.Unlock()
- delete(merchantMap, appKey)
- }
- /*func clearPriceMap(appKey string) {
- merchantId := int64(0)
- o := orm.NewOrm()
- err := o.Raw("select id from t_gd_merchants where app_key=?", appKey).QueryRow(&merchantId)
- if err != nil {
- return
- }
- priceMutex.Lock()
- defer priceMutex.Unlock()
- delete(priceMap, merchantId)
- }*/
- // clearMerchantApiMap 删除本地缓存的某个商户的api
- func clearMerchantApiMap(apiId int64, merchantId int64) {
- merchantApiMutex.Lock()
- defer merchantApiMutex.Unlock()
- key := fmt.Sprintf("%d-%d", apiId, merchantId)
- delete(merchantApiMap, key)
- }
- // handleApiNotify 处理基础api的消息通知
- func handleApiNotify(data string) {
- m := map[string]string{}
- json.Unmarshal([]byte(data), &m)
- if m["router"] != "" && m["method"] != "" {
- clearApiMap(m["router"], m["method"])
- }
- }
- // handleMerchantNotify 处理商户的消息通知
- func handleMerchantNotify(data string) {
- if data != "" {
- clearMerchantMap(data)
- //clearPriceMap(data)
- }
- }
- // handleMerchantApiNotify 处理商户api的消息通知
- func handleMerchantApiNotify(data string) {
- m := map[string]interface{}{}
- json.Unmarshal([]byte(data), &m)
- if _, ok := m["api_id"]; ok == false {
- return
- }
- if _, ok := m["merchant_id"]; ok == false {
- return
- }
- f, _ := m["api_id"].(float64)
- apiId := int64(f)
- f, _ = m["merchant_id"].(float64)
- merchantId := int64(f)
- clearMerchantApiMap(apiId, merchantId)
- }
- // Watch 订阅基础api,商户,商户api的消息
- func Watch() {
- go func() {
- cache.Redis.RegisterFunc(ApiNotifyChannel, handleApiNotify)
- cache.Redis.RegisterFunc(MerchantNotifyChannel, handleMerchantNotify)
- cache.Redis.RegisterFunc(MerchantApiNotifyChannel, handleMerchantApiNotify)
- cache.Redis.SubscribeAndHandle(ApiNotifyChannel, MerchantNotifyChannel, MerchantApiNotifyChannel)
- }()
- }
- // getAccessCountInfo 获取商户数据api的用量信息
- func getAccessCountInfo(o orm.Ormer, mdaId int64) (totalUsed int, dayUsed int, specialDayUsed int, totalId int64, dayId int64, dayTotalUsed int64, dayTotalUsedDayCombo int64, err error) {
- sql := "select id, count, day_count as special_day_count, day_total_count from t_gd_api_access_count where merchant_data_api_id=? and create_time=?"
- totalTime := "0000-00-00"
- dayTime := time.Now().Format("2006-01-02")
- err = o.Raw(sql, mdaId, totalTime).QueryRow(&totalId, &totalUsed, &specialDayUsed, &dayTotalUsed)
- if err != nil {
- if err != orm.ErrNoRows {
- err = errors.DataBaseError
- return
- }
- }
- sql = "select id, count, day_total_count from t_gd_api_access_count where merchant_data_api_id=? and create_time=?"
- err = o.Raw(sql, mdaId, dayTime).QueryRow(&dayId, &dayUsed, &dayTotalUsedDayCombo)
- if err != nil {
- if err != orm.ErrNoRows {
- err = errors.DataBaseError
- return
- }
- }
- err = nil
- return
- }
- // setExpire 设置数据api状态为过期
- func setExpire(o orm.Ormer, mdaId int64) {
- o.Raw("update t_gd_merchant_data_api set state=1 where id=?", mdaId).Exec()
- }
- // setState 设置数据api状态为正常
- func setState(o orm.Ormer, mdaId int64) {
- o.Raw("update t_gd_merchant_data_api set state=0 where id=?", mdaId).Exec()
- }
- // checkTime 用量检查, info 包含套餐信息, state为数据api的原始状态
- func checkTime(o orm.Ormer, info timeInfo, state int) (ret checkTimeResult, err error) {
- now := time.Now().Unix()
- nowday := time.Now().Format("2006-01-02")
- updated := false
- defer func() {
- if updated == false {
- return
- }
- if err == nil {
- return
- }
- // 商户类型为预结算或者后付款次数不回退
- /*if (merchantType == 2 || merchantType == 3) && err == errors.CheckApiDayCountLimitNew{
- return
- }*/
- // 如果超出次数限制,次数减一
- sql := ""
- if info.comboType == 2 {
- sql = fmt.Sprintf("update t_gd_api_access_count set count= case when count > 0 then count - 1 when count=0 then 0 end, day_total_count= case when day_total_count > 0 then day_total_count - 1 else 0 end where merchant_data_api_id=%d and create_time<>'0000-00-00'", info.mdaId)
- } else {
- sql = fmt.Sprintf("update t_gd_api_access_count set count= case when count > 0 then count - 1 when count=0 then 0 end, day_count= case when day_count > 0 then day_count - 1 else 0 end, day_total_count= case when day_total_count > 0 then day_total_count - 1 else 0 end where merchant_data_api_id=%d and create_time='0000-00-00'", info.mdaId)
- }
- o.Raw(sql).Exec()
- }()
- // 初始化套餐类型
- if info.comboType == 0 {
- if info.endTime == 0 {
- info.comboType = 1
- } else {
- info.comboType = 2
- }
- }
- // 免费套餐直接通过
- if info.isFree > 0 {
- ret.info = info
- return ret, nil
- }
- ret.comboType = info.comboType
- // 按天套餐天数过期,直接返错
- if now > info.endTime && info.comboType == 2 {
- if state != 0 {
- return ret, errors.CheckApiDaysLimit
- }
- setExpire(o, info.mdaId)
- return ret, errors.CheckApiDaysLimit
- }
- sql := ""
- // 次数记录不存在则创建
- if info.comboType == 2 {
- sql = fmt.Sprintf("insert into t_gd_api_access_count(fail_count,"+
- " count, day_total_count, merchant_data_api_id, create_time) select 0, 0, 0, %d, '%s' "+
- "from dual where not exists (select * from t_gd_api_access_count where create_time <> '0000-00-00' and merchant_data_api_id = %d)",
- info.mdaId, nowday, info.mdaId)
- } else {
- sql = fmt.Sprintf("insert into t_gd_api_access_count(fail_count, "+
- "count, day_total_count, merchant_data_api_id, create_time, day_count, now_date) select 0, 0, 0, %d, '0000-00-00', 0, '%s' "+
- "from dual where not exists (select * from t_gd_api_access_count where create_time = '0000-00-00' and merchant_data_api_id = %d)",
- info.mdaId, nowday, info.mdaId)
- }
- _, err = o.Raw(sql).Exec()
- if err != nil && strings.Contains(err.Error(), "Duplicate") == false {
- return ret, errors.DataBaseError
- }
- // 首先将次数加1,限制并发下商户次数
- if info.comboType == 2 {
- sql = fmt.Sprintf("update t_gd_api_access_count set last_day_count= case when create_time ='%s' then last_day_count else count end, last_day_date=case when create_time='%s' then last_day_date else create_time end, count=case when"+
- " create_time <>'%s' then 1 when create_time='%s' then count+1 end, "+
- "day_total_count = case when create_time <>'%s' then 1 when create_time='%s' then day_total_count+1 end, "+
- "create_time='%s',fail_count= case when create_time <>'%s' then 0 when"+
- " create_time='%s' then fail_count end, create_time='%s' where merchant_data_api_id=%d and create_time<>'0000-00-00'", nowday, nowday, nowday, nowday, nowday, nowday, nowday, nowday, nowday, nowday, info.mdaId)
- } else {
- sql = fmt.Sprintf("update t_gd_api_access_count set last_day_count= case when now_date ='%s' then last_day_count else day_count end, last_day_date=case when now_date='%s' then last_day_date else now_date end, count=count+1, day_count= case when now_date='%s' then day_count+1 else 1 end,day_total_count= case when now_date='%s' then day_total_count+1 else 1 end, now_date= '%s' where merchant_data_api_id=%d and create_time='0000-00-00'", nowday, nowday, nowday, nowday, nowday, info.mdaId)
- }
- _, err = o.Raw(sql).Exec()
- if err != nil {
- return ret, errors.DataBaseError
- }
- updated = true
- // 获取已用次数信息
- totalUsed, dayUsed, specialDayUsed, totalId, dayId, dayTotalUsed, dayTotalUsedDayCombo, err := getAccessCountInfo(o, info.mdaId)
- if err != nil {
- return ret, err
- }
- ret.remainCount = info.totalCount - totalUsed + 1
- ret.remainDayCount = info.dayCount - dayUsed + 1
- ret.remainDays = int((info.endTime - now) / int64(3600*24))
- ret.totalDays = int((info.endTime - info.startTime) / int64(3600*24))
- ret.info = info
- if ret.comboType == 1 {
- // 按次套餐单日即查量超次
- // TODO
- if info.dayTotalCount > 0 && info.dayTotalCount-int(dayTotalUsed)+1 <= 0 {
- return ret, errors.CheckApiDayCountLimit
- }
- // 单日计费次数超次
- // TODO
- if info.dayCount > 0 && info.dayCount-specialDayUsed+1 <= 0 {
- return ret, errors.CheckApiDayCountLimit
- }
- // 状态已过期
- if state != 0 {
- return ret, errors.CheckApiTotalCountLimit
- }
- // 总计费次数超次
- if ret.remainCount <= 0 {
- setExpire(o, info.mdaId)
- return ret, errors.CheckApiTotalCountLimit
- }
- ret.accessCountId = totalId
- return ret, nil
- }
- // 按天套餐按日即查次数超次
- // TODO
- if info.dayTotalCount > 0 && info.dayTotalCount-int(dayTotalUsedDayCombo)+1 <= 0 {
- return ret, errors.CheckApiDayCountLimit
- }
- // 未超次,则恢复状态
- if state != 0 {
- if ret.remainDayCount > 0 {
- setState(o, info.mdaId)
- }
- }
- // 按天套餐单日计费次数超次
- if ret.remainDayCount <= 0 {
- return ret, errors.CheckApiDayCountLimit
- }
- ret.accessCountId = dayId
- return ret, nil
- }
- func getMerchantInfoFromMysql(o orm.Ormer, appKey string) (*MerchantInfo, error) {
- minfo := MerchantInfo{}
- if appKey == "" {
- return nil, nil
- }
- sql := "select id, app_secret, merchant_name, ip_whitelist,is_http_code,merchant_type,arrearage,auth_status from t_gd_merchants where app_key=?"
- err := o.Raw(sql, appKey).QueryRow(&minfo)
- if err != nil {
- if err == orm.ErrNoRows {
- return nil, errors.CheckMerchantNotExist
- }
- setMysqlError(sql, fmt.Sprintf("%s", appKey), err)
- return nil, errors.DataBaseError
- }
- if minfo.Id > 0 {
- setMerchantMap(appKey, &minfo)
- }
- return &minfo, nil
- }
- // getMerchantInfo 根据appKey获取商户信息
- func getMerchantInfo(o orm.Ormer, appKey string) (*MerchantInfo, error) {
- minfo := MerchantInfo{}
- if appKey == "" {
- return nil, nil
- }
- if minfo := getMerchantFromMap(appKey); minfo != nil {
- return minfo, nil
- }
- key := fmt.Sprintf("t_gd_merchants-%s", appKey)
- tab := apis.TGdMerchants{}
- utils.RedisGet(key, &tab)
- if tab.Id == 0 {
- return getMerchantInfoFromMysql(o, appKey)
- }
- minfo.Id = tab.Id
- minfo.AppSecret = tab.AppSecret
- minfo.MerchantName = tab.MerchantName
- minfo.IpWhitelist = tab.IpWhitelist
- minfo.IsHttpCode = tab.IsHttpCode
- minfo.MerchantType = tab.MerchantType
- minfo.Arrearage = tab.Arrearage
- minfo.AuthStatus = tab.AuthStatus
- if minfo.Id > 0 {
- setMerchantMap(appKey, &minfo)
- }
- return &minfo, nil
- }
- // getBaseApiIdFromMysql 从mysql获取基础api id等信息
- func getBaseApiIdFromMysql(o orm.Ormer, req *apis.ManagementCheckApiReq) (int64, bool, string, error) {
- var baseApiId int64
- var enable bool
- name := ""
- sql := "select id, enable, name from t_gd_api where router=? and method=?"
- err := o.Raw(sql, req.Router, req.Method).QueryRow(&baseApiId, &enable, &name)
- if err != nil {
- if err == orm.ErrNoRows {
- return 0, false, "", errors.CheckApiNotExist
- }
- setMysqlError(sql, fmt.Sprintf("%s %s", req.Router, req.Method), err)
- return 0, false, "", errors.DataBaseError
- }
- if baseApiId > 0 {
- setApiMap(req.Router, req.Method, baseApiId, name, enable)
- }
- return baseApiId, enable, name, nil
- }
- // getBaseApiId 获取基础api id等信息
- func getBaseApiId(o orm.Ormer, req *apis.ManagementCheckApiReq) (int64, bool, string, error) {
- if api := getApiFromMap(req.Router, req.Method); api != nil {
- return api.apiId, api.enable, api.apiName, nil
- }
- key := fmt.Sprintf("t_gd_api-%s-%s", req.Method, req.Router)
- tab := apis.TGdApi{}
- utils.RedisGet(key, &tab)
- if tab.Id == 0 {
- return getBaseApiIdFromMysql(o, req)
- }
- if tab.Id > 0 {
- setApiMap(req.Router, req.Method, tab.Id, tab.Name, tab.Enable)
- }
- return tab.Id, tab.Enable, tab.Name, nil
- }
- // getResultMaps 获取商户api相关信息,minfo包含了商户信息,isCache表示是否使用本地缓存
- func getResultMaps(o orm.Ormer, req *apis.ManagementCheckApiReq, minfo *MerchantInfo, isCache bool) ([]orm.Params, int64, error) {
- var baseApiId int64
- var enable bool
- // TODO 获取商户api 单价
- if minfo == nil {
- return nil, 0, nil
- }
- merchantId := minfo.Id
- // 获取基础api信息
- baseApiId, enable, apiname, err := getBaseApiId(o, req)
- if err != nil {
- return nil, baseApiId, err
- }
- minfo.ApiName = apiname
- // 基础api未启用
- if enable == false {
- return nil, baseApiId, errors.CheckApiNotEnable
- }
- // 从本地缓存获取商户api信息
- if isCache {
- if maps := getMerchantApiFromMap(baseApiId, merchantId); len(maps) > 0 {
- return maps, baseApiId, nil
- }
- }
- maps := []orm.Params{}
- /*
- sql = "select a.id, a.merchant_data_api_id, a.count_type, a.count_code, a.is_crypto, a.is_enable, a.force_update, a.request_param, a.response_param, b.count as total_count, b.count_per_day as day_count, b.start_time, b.end_time from t_gd_merchant_child_data_api as a inner join t_gd_merchant_data_api as b on a.merchant_data_api_id=b.id where a.api_id=? and b.merchant_id=?"
- */
- sql := "select a.id, a.filter, a.merchant_data_api_id, b.ip_whitelist, b.ip_whitelist_enable, a.count_type, a.count_code, a.is_crypto, " +
- "a.is_enable, a.force_update, a.reuse_time, a.request_param, a.response_param,a.timeout,a.minimal_time_consuming,a.random_percentage,a.is_raw_error_code, (select is_free" +
- " from t_gd_data_api_query_type where id=b.query_type_id) as is_free, b.count as total_count, " +
- "b.count_per_day as day_count, b.state as api_state, b.combo_type, b.start_time, b.end_time, b.day_total_count,b.unit_price from " +
- "t_gd_merchant_child_data_api as a inner join t_gd_merchant_data_api as b on a.merchant_data_api_id=b.id where a.api_id=? and b.merchant_id=?"
- _, err = o.Raw(sql, baseApiId, merchantId).Values(&maps)
- if err != nil {
- if err == orm.ErrNoRows {
- return nil, baseApiId, errors.CheckApiInfoNotExist
- }
- setMysqlError(sql, fmt.Sprintf("%d %d", baseApiId, merchantId), err)
- return nil, baseApiId, errors.DataBaseError
- }
- if len(maps) == 0 {
- return nil, baseApiId, errors.CheckApiInfoNotExist
- }
- if len(maps) > 0 {
- setMerchantApiMap(baseApiId, merchantId, maps)
- }
- return maps, baseApiId, nil
- }
- // getOriginMerchantApi 获取原始商户的一条数据api信息
- // 数据查询中支持使用原始商户的api配置,计费算到内部商户(又称替换商户)头上
- func getOriginMerchantApi(o orm.Ormer, req *apis.ManagementCheckApiReq, maps []orm.Params, minfo *MerchantInfo) (orm.Params, error) {
- var checkTimeError error
- var matchedRecord orm.Params
- for _, v := range maps {
- minfo.MerchantChildApiId = int64(ormStringToInt(v, "id"))
- matchedRecord = v
- break
- }
- return matchedRecord, checkTimeError
- }
- // getAvailableApi 商户如果购买了多个包含相同基础api的数据api,任意选一个可用的
- func getAvailableApi(o orm.Ormer, req *apis.ManagementCheckApiReq, maps []orm.Params, minfo *MerchantInfo) (orm.Params, checkTimeResult, error) {
- var checkTimeError error
- var ctr checkTimeResult
- var matchedRecord orm.Params
- for _, v := range maps {
- // 初始化套餐信息
- info := timeInfo{
- startTime: ormStringToInt(v, "start_time"),
- endTime: ormStringToInt(v, "end_time"),
- comboType: int(ormStringToInt(v, "combo_type")),
- mdaId: int64(ormStringToInt(v, "merchant_data_api_id")),
- dayCount: int(ormStringToInt(v, "day_count")),
- totalCount: int(ormStringToInt(v, "total_count")),
- isFree: int(ormStringToInt(v, "is_free")),
- dayTotalCount: int(ormStringToInt(v, "day_total_count")),
- }
- matchedRecord = v
- minfo.MerchantChildApiId = int64(ormStringToInt(v, "id"))
- isIpWhitelistEnable := int(ormStringToInt(v, "ip_whitelist_enable"))
- // ip报名单检查
- if value, ok := v["ip_whitelist"]; ok && isIpWhitelistEnable == 1 {
- ipWhitelist, _ := value.(string)
- if ipWhitelist != "" && checkIpWhite(ipWhitelist, req.Ip) == false {
- checkTimeError = errors.IpAddrErr
- continue
- }
- }
- // api是否启用
- if int(ormStringToInt(v, "is_enable")) == 0 {
- checkTimeError = errors.CheckApiNotEnable
- continue
- }
- // api是否过期
- ctr, checkTimeError = checkTime(o, info, int(ormStringToInt(v, "api_state")))
- ctr.info = info
- if checkTimeError != nil {
- continue
- }
- //matchedRecord = v
- break
- }
- return matchedRecord, ctr, checkTimeError
- }
- // setCheckResult 设置公共校验完成后的返回参数
- func setCheckResult(ctr checkTimeResult, matchedRecord orm.Params) (apis.CheckMerchantApiResult, error) {
- var err error
- result := apis.CheckMerchantApiResult{}
- reqParamConf, _ := matchedRecord["request_param"].(string)
- resParamConf, _ := matchedRecord["response_param"].(string)
- result.MerchantChildApiId = ormStringToInt(matchedRecord, "id")
- result.ComboType = ctr.comboType
- result.CountType = int(ormStringToInt(matchedRecord, "count_type"))
- result.CountCode, _ = matchedRecord["count_code"].(string)
- result.ReuseTime = int(ormStringToInt(matchedRecord, "reuse_time"))
- result.Timeout = uint64(ormStringToInt(matchedRecord, "timeout"))
- result.MinimalTimeConsuming = int(ormStringToInt(matchedRecord, "minimal_time_consuming"))
- result.RandomPercentage = int(ormStringToInt(matchedRecord, "random_percentage"))
- if int(ormStringToInt(matchedRecord, "is_raw_error_code")) == 1 {
- result.IsRawErrorCode = true
- }
- if int(ormStringToInt(matchedRecord, "force_update")) == 1 {
- result.IsForceUpdate = true
- }
- if result.RequstParamConf, err = parseParamConf(reqParamConf); err != nil {
- return result, err
- }
- if result.ResponseParamConf, err = parseParamConf(resParamConf); err != nil {
- return result, err
- }
- //result.ProviderInfo = providers
- return result, nil
- }
- // parseParamConf 将配置参数字符串转为json数组
- func parseParamConf(data string) ([]apis.ManagementBaseApiParam, error) {
- params := []apis.ManagementBaseApiParam{}
- err := json.Unmarshal([]byte(data), ¶ms)
- if err != nil {
- return nil, errors.CheckApiParamConfParseFailed
- }
- return params, nil
- }
- // 判断实际数据是否加密,加密返回解密后数据和true, 未加密返回原数据
- func isActualEncrypt(data []byte, secret []byte) ([]byte, bool) {
- bytes, err := hex.DecodeString(string(data))
- if err != nil {
- return data, false
- }
- paramBytes, err := config.AesDecrypt(bytes, secret)
- if err != nil {
- return data, false
- }
- return paramBytes, true
- }
- // decryptParam 解密参数
- func decryptParam(req *apis.ManagementCheckApiReq, secret []byte, isCrypto int) (paramBytes []byte, err error) {
- // 加密
- var origin = map[string]string{}
- // 原始参数解析
- json.Unmarshal(req.RequestParam, &origin)
- enType := req.Header["encrypt_type"]
- // 非加密模式
- if enType == ""{
- return req.RequestParam, nil
- }
- for k,v := range origin{
- if v != "" {
- if enType == "MD5"{
- }else if enType == "AES"{
- bytes, err := hex.DecodeString(v)
- if err != nil {
- return nil,errors.CheckParamDecryptFail
- }
- desBytes, err := config.AesDecrypt(bytes, secret)
- if err != nil {
- return nil,errors.CheckParamDecryptFail
- }
- origin[k] = string(desBytes)
- }else{
- return nil,errors.CryptoTypeFailed
- }
- }
- }
- return json.Marshal(origin)
- return req.RequestParam, nil
- }
- // decreaseCount api调用量减一
- // 因为公共校验时会先将api用量加一(防止并发引起的多调),当校验不通过时会减一
- func decreaseCount(o orm.Ormer, id int64) {
- if id <= 0 {
- return
- }
- o.Raw("update t_gd_api_access_count set count= case when count>0 then count - 1 when count=0 then 0 end, day_total_count = case when day_total_count > 0 then day_total_count -1 else 0 end, day_count = case when day_count > 0 then day_count - 1 else 0 end where id=?", id).Exec()
- }
- func increaseBalance(o orm.Ormer, merchantDataApiId, merchantId int64, unitPrice float64, error error) {
- sql := fmt.Sprintf("update t_gd_merchants set balance=balance+%f where id=?", unitPrice)
- o.Raw(sql, merchantId).Exec()
- var e jsonrpc2.Error
- err := json.Unmarshal([]byte(error.Error()), &e)
- if err == nil {
- if e.Code == 1102 || e.Code == 1103 || e.Code == 1023 {
- if merchantDataApiId == 0 || merchantId == 0 {
- return
- }
- timeNow := time.Now()
- day := timeNow.Format("2006-01-02")
- month := timeNow.Format("2006-01")
- sql = "insert into t_gd_consume(day,month,merchant_data_api_id,merchant_id,total_count,remark) " +
- "value ('%s','%s',%d,%d,1,'') ON DUPLICATE key UPDATE total_count=total_count+1"
- sql = fmt.Sprintf(sql, day, month, merchantDataApiId, merchantId)
- _, err = o.Raw(sql).Exec()
- }
- }
- }
- func checkBalance(o orm.Ormer, merchantType int, merchantId int64, unitPrice, arrearage float64, info timeInfo, comboType int) error {
- timeNow := time.Now()
- day := timeNow.Format("2006-01-02")
- totalCount := 0
- chargeCount := 0
- sql := "select total_count, charge_count from t_gd_consume where day=? and merchant_data_api_id=?"
- err := o.Raw(sql, day, info.mdaId).QueryRow(&totalCount, &chargeCount)
- if err == nil {
- // 单日计费次数超次
- if info.dayTotalCount > 0 && info.dayTotalCount <= totalCount {
- return errors.CheckApiDayCountLimit
- }
- if comboType == 1 {
- if info.dayCount > 0 && info.dayCount <= chargeCount {
- return errors.CheckApiDayCountLimit
- }
- }
- }
- // 预付款
- if unitPrice == 0 {
- return nil
- }
- if merchantType == 2 {
- sql := fmt.Sprintf("update t_gd_merchants set balance=balance-%f where id=? and balance-%f>=0", unitPrice, unitPrice)
- if arrearage != 0 {
- sql = fmt.Sprintf("update t_gd_merchants set balance=balance-%f where id=? and balance-%f>=%f", unitPrice, unitPrice, -arrearage)
- }
- result, err := o.Raw(sql, merchantId).Exec()
- if err != nil {
- return errors.DataBaseError
- }
- row, _ := result.RowsAffected()
- if row == 0 {
- return errors.BalanceError
- }
- } else {
- // 后结算
- sql := fmt.Sprintf("update t_gd_merchants set balance=balance-%f where id=?", unitPrice)
- if arrearage != 0 {
- sql = fmt.Sprintf("update t_gd_merchants set balance=balance-%f where id=? and balance-%f>=%f", unitPrice, unitPrice, -arrearage)
- }
- result, err := o.Raw(sql, merchantId).Exec()
- if err != nil {
- return errors.DataBaseError
- }
- row, _ := result.RowsAffected()
- if row == 0 {
- return errors.ArrearageError
- }
- }
- return nil
- }
- func RobotMsg(content string) (err error) {
- body := map[string]interface{}{
- "msgtype": "text",
- "text": map[string]interface{}{"content": content},
- }
- bytes, _ := json.Marshal(body)
- h := utils.HttpRequestWithHeadCommon{
- Method: "POST",
- Url: config.Conf.ThirdPart.RobotUrl,
- Body: bytes,
- TimeOut: 10 * time.Second,
- }
- bytes, err = h.Request()
- if err != nil {
- l.Error("func",
- zap.String("call", "RobotMsg"),
- zap.String("params", content),
- zap.String("error", err.Error()))
- return errors.VendorError
- }
- errcode := gjson.GetBytes(bytes, "errcode").Int()
- errmsg := gjson.GetBytes(bytes, "errmsg").String()
- if errcode != 0 {
- l.Error("func",
- zap.String("call", "RobotMsg"),
- zap.String("params", content),
- zap.String("error", errmsg))
- return errors.VendorError
- }
- return nil
- }
- func balanceCheckSendDingTalk(o orm.Ormer, merchantId int64, unitPrice, arrearage float64, merchantType int) {
- if merchantType == 3 {
- if arrearage == 0 {
- return
- }
- }
- // 抓异常代码
- defer func() {
- if r := recover(); r != nil {
- fmt.Println("err :", r)
- }
- }()
- //priceMutex.Lock()
- //defer priceMutex.Unlock()
- //ret, ok := priceMap[merchantId]
- //if ok == false {
- balance := float64(0)
- err := o.Raw("select balance from t_gd_merchants where id=?", merchantId).QueryRow(&balance)
- if err != nil {
- fmt.Println("err:", err)
- return
- }
- // ret = balance
- //}else {
- // ret = ret - unitPrice
- //}
- //priceMap[merchantId] = ret
- if (balance + arrearage) <= 10 {
- // 发送钉钉消息
- key := fmt.Sprintf("dingding-%d", merchantId)
- isSucess, err := utils.RedisSetNxEx(key, 864000, "1")
- if err != nil {
- fmt.Println("err:", err)
- return
- }
- if isSucess {
- merchantName := ""
- err = o.Raw("select merchant_name from t_gd_merchants where id=?", merchantId).QueryRow(&merchantName)
- if err != nil {
- fmt.Println("err:", err)
- return
- }
- content := fmt.Sprintf("商户(%s)余额不足", merchantName)
- _ = RobotMsg(content)
- //d := ding.Webhook{AccessToken: config.Conf.ThirdPart.DingDing.AccessToken, Secret: config.Conf.ThirdPart.DingDing.Secret}
- //_ = d.SendMessage(content)
- //SendToDingTalk(content)
- }
- }
- }
- // getResultInfos 获取公共校验结果
- func getResultInfos(o orm.Ormer, req *apis.ManagementCheckApiReq, reply *apis.ManagementCheckApiReply, minfo *MerchantInfo, isCache bool, appKey string) error {
- // 获取商户api原始信息
- maps, baseApiId, err := getResultMaps(o, req, minfo, isCache)
- defer func() {
- maps = nil
- }()
- reply.MerchantApiInfo.BaseApiId = baseApiId
- if err != nil {
- return err
- }
- feeType := 1
- // 从原始信息中获取一条可用的记录
- matchedRecord, ctr, err := getAvailableApi(o, req, maps, minfo)
- if err == errors.IpAddrErr || err == errors.CheckApiNotEnable {
- return err
- }
- //unitPrice := float64(100)
- unitPrice := float64(ormStringToFloat(matchedRecord, "unit_price"))
- if int(ormStringToInt(matchedRecord, "is_raw_error_code")) == 1 {
- reply.MerchantApiInfo.IsRawErrorCode = true
- }
- // 可欠费金额
- arrearage := minfo.Arrearage
- if err != nil {
- // TODO 检查是否是按收费
- if minfo.MerchantType == 2 || minfo.MerchantType == 3 {
- err = checkBalance(o, minfo.MerchantType, minfo.Id, unitPrice, arrearage, ctr.info, ctr.comboType)
- if err == nil || err == errors.ArrearageError || err == errors.BalanceError {
- go balanceCheckSendDingTalk(o, minfo.Id, unitPrice, arrearage, minfo.MerchantType)
- }
- if err != nil {
- return err
- }
- feeType = 2
- } else {
- return err
- }
- }
- // 参数解密
- isCrypto := int(ormStringToInt(matchedRecord, "is_crypto"))
- paramBytes, err := decryptParam(req, []byte(minfo.AppSecret), isCrypto)
- if err != nil {
- // 商户为普通商户
- if feeType == 1 {
- decreaseCount(o, ctr.accessCountId)
- } else {
- // TODO 返钱
- increaseBalance(o, 0, minfo.Id, unitPrice, err)
- }
- return err
- }
- // 设置部分校验结果
- result, err := setCheckResult(ctr, matchedRecord)
- if isCrypto == 1 {
- result.IsCrypto = true
- }
- result.AppSecret = minfo.AppSecret
- result.MerchantId = minfo.Id
- result.BaseApiId = baseApiId
- result.DecryptParam = paramBytes
- result.UnitPrice = unitPrice
- reply.MerchantApiInfo = result
- reply.MerchantApiInfo.AccessCountId = ctr.accessCountId
- reply.MerchantApiInfo.MerchantDataApiId = ctr.info.mdaId
- if err != nil {
- // 扣次
- if feeType == 1 {
- decreaseCount(o, ctr.accessCountId)
- } else {
- // TODO 返钱
- increaseBalance(o, reply.MerchantApiInfo.MerchantDataApiId, minfo.Id, unitPrice, err)
- }
- return err
- }
- // 参数公共检查
- filters := []apis.BaseApiParamFilter{}
- filterString, _ := matchedRecord["filter"].(string)
- if filterString != "" {
- json.Unmarshal([]byte(filterString), &filters)
- }
- requestBytes, err := utils.GetRequestParamNew(reply.MerchantApiInfo, filters, paramBytes, filterRuleMap)
- if err != nil {
- // 扣次
- if feeType == 1 {
- decreaseCount(o, ctr.accessCountId)
- } else {
- // TODO 返钱
- increaseBalance(o, reply.MerchantApiInfo.MerchantDataApiId, minfo.Id, unitPrice, err)
- }
- return err
- }
- err, token := limit.Allow(req.Router, appKey)
- if err != nil {
- // 扣次
- if feeType == 1 {
- decreaseCount(o, ctr.accessCountId)
- } else {
- increaseBalance(o, reply.MerchantApiInfo.MerchantDataApiId, minfo.Id, unitPrice, err)
- }
- return err
- }
- reply.MerchantApiInfo.Token = *token
- reply.MerchantApiInfo.DecryptParam = requestBytes
- reply.MerchantApiInfo.FeeType = feeType
- return nil
- }
- // getReplaceResultInfos 使用内部商户扣费时,获取公共校验结果
- func getReplaceResultInfos(o orm.Ormer, req *apis.ManagementCheckApiReq, reply *apis.ManagementCheckApiReply, minfo *MerchantInfo, rminfo *MerchantInfo, isCache bool) error {
- // 获取原始商户的api信息(一条或多条记录)
- maps, baseApiId, err := getResultMaps(o, req, minfo, isCache)
- defer func() {
- maps = nil
- }()
- reply.MerchantApiInfo.BaseApiId = baseApiId
- if err != nil {
- return err
- }
- // 获取内部商户的api信息(一条或多条记录)
- rmaps, rbaseApiId, err := getResultMaps(o, req, rminfo, isCache)
- defer func() {
- rmaps = nil
- }()
- if err != nil {
- return err
- }
- // 获取一条原始商户api信息
- originRecord, err := getOriginMerchantApi(o, req, maps, minfo)
- if err != nil {
- return err
- }
- // 获取一条可用的记录
- replaceRecord, ctr, err := getAvailableApi(o, req, rmaps, rminfo)
- if int(ormStringToInt(replaceRecord, "is_raw_error_code")) == 1 {
- reply.MerchantApiInfo.IsRawErrorCode = true
- }
- if err != nil {
- return err
- }
- // 参数解密
- isCrypto := int(ormStringToInt(originRecord, "is_crypto"))
- paramBytes, err := decryptParam(req, []byte(minfo.AppSecret), isCrypto)
- if err != nil {
- decreaseCount(o, ctr.accessCountId)
- return err
- }
- // 设置部分校验结果
- result, err := setCheckResult(ctr, originRecord)
- if isCrypto == 1 {
- result.IsCrypto = true
- }
- result.AppSecret = minfo.AppSecret
- result.MerchantId = minfo.Id
- result.BaseApiId = baseApiId
- result.DecryptParam = paramBytes
- reply.MerchantApiInfo = result
- reply.MerchantApiInfo.AccessCountId = ctr.accessCountId
- reply.MerchantApiInfo.ReplaceInfo.ReplaceBaseApiId = rbaseApiId
- reply.MerchantApiInfo.ReplaceInfo.ReplaceMerchantId = rminfo.Id
- reply.MerchantApiInfo.ReplaceInfo.ReplaceMerchantDataApiId = ctr.info.mdaId
- reply.MerchantApiInfo.ReplaceInfo.ReplaceMerchantChildApiId = ormStringToInt(replaceRecord, "id")
- reply.MerchantApiInfo.MerchantDataApiId = int64(ormStringToInt(originRecord, "merchant_data_api_id"))
- if err != nil {
- decreaseCount(o, ctr.accessCountId)
- return err
- }
- // 公共参数检查
- filters := []apis.BaseApiParamFilter{}
- filterString, _ := originRecord["filter"].(string)
- if filterString != "" {
- json.Unmarshal([]byte(filterString), &filters)
- }
- requestBytes, err := utils.GetRequestParamNew(reply.MerchantApiInfo, filters, paramBytes, filterRuleMap)
- if err != nil {
- decreaseCount(o, ctr.accessCountId)
- return err
- }
- reply.MerchantApiInfo.DecryptParam = requestBytes
- return nil
- }
- func signCheck(req *apis.ManagementCheckApiReq, secret string, appKey string) error {
- ts := ""
- ok := false
- sign := ""
- if sign, ok = req.Header["sign"]; ok {
- if sign == ""{
- return nil
- }
- }else{
- return nil
- }
- /*if isSign, ok := req.Header["is_sign"]; ok {
- if isSign == "0" {
- if sign == secret {
- return nil
- } else {
- return errors.CheckSignFailed
- }
- }
- }*/
- if ts, ok = req.Header["ts"]; ok == false {
- return errors.ArgsError
- }
- m := map[string]string{}
- json.Unmarshal(req.RequestParam,&m)
- var keyList []string
- for k,_ := range m{
- keyList = append(keyList,k)
- }
- sort.Strings(keyList)
- //fmt.Println("keylist :",keyList)
- signParam := ""
- for _,v := range keyList{
- signParam = signParam + v+m[v]
- }
- //fmt.Println("sign param :",signParam)
- signtext := fmt.Sprintf("%s%s%s%s", appKey,secret, ts,signParam)
- signcomput := utils.MD5(signtext)
- if signcomput != strings.ToLower(sign) {
- return errors.CheckSignFailed
- }
- return nil
- }
- type MerchantInfo struct {
- Id int64 `json:"id"`
- AppSecret string `json:"app_secret"`
- MerchantName string `json:"merchant_name"`
- IpWhitelist string `json:"ip_whitelist"`
- Email string `json:"email"`
- ApiName string `json:"api_name"`
- MerchantChildApiId int64 `json:"merchant_child_api_id"`
- IsHttpCode int `json:"is_http_code"`
- // TODO 获取商户类型
- MerchantType int `json:"merchant_type"`
- Arrearage float64 `json:"arrearage"` // 可欠费金额
- AuthStatus int `json:"auth_status" description:"认证状态0 待认证,1认证通过, 2认证不通过"`
- }
- // replaceMerchantId 将商户id替换为内部商户id
- func replaceMerchantId(req *apis.ManagementCheckApiReq, reply *apis.ManagementCheckApiReply) {
- r, _ := req.Header["replace_app_key"]
- if r == "" {
- return
- }
- if reply.MerchantApiInfo.ReplaceInfo.ReplaceMerchantId > 0 {
- reply.MerchantApiInfo.MerchantId = reply.MerchantApiInfo.ReplaceInfo.ReplaceMerchantId
- }
- }
- // ipv4ToArray ip字符串转为数组
- func ipv4ToArray(ip string) []int {
- array := strings.Split(ip, ".")
- if len(array) != 4 {
- return nil
- }
- ret := [4]int{}
- var err error
- for i, v := range array {
- ret[i], err = strconv.Atoi(v)
- if err != nil {
- return nil
- }
- }
- return ret[:]
- }
- // checkIpSegment ip段检查, 参数中start, end为白名单中的起止ip, ip为客户实际ip
- func checkIpSegment(start, end, ip string) bool {
- // 开始ip转为ip数组
- startArray := ipv4ToArray(start)
- if len(startArray) != 4 {
- return false
- }
- // 结束ip转为ip数组
- endArray := ipv4ToArray(end)
- if len(endArray) != 4 {
- return false
- }
- // 实际ip转为ip数组
- ipArray := ipv4ToArray(ip)
- if len(ipArray) != 4 {
- return false
- }
- // 判断ip是否在起止ip段中
- for i, v := range startArray {
- if startArray[i] == endArray[i] {
- if ipArray[i] != v {
- return false
- }
- continue
- }
- if ipArray[i] < v || ipArray[i] > endArray[i] {
- return false
- }
- }
- return true
- }
- // checkIpWhite ip白名单检查
- func checkIpWhite(iplist string, ip string) bool {
- array := strings.Split(iplist, ",")
- for _, ipseg := range array {
- ipsegArray := strings.Split(ipseg, "-")
- if len(ipsegArray) == 1 {
- if ipsegArray[0] == ip {
- return true
- }
- continue
- }
- if len(ipsegArray) == 0 {
- continue
- }
- if checkIpSegment(ipsegArray[0], ipsegArray[1], ip) {
- return true
- }
- }
- return false
- }
- // ManagementCheckApi 公共校验
- // 商户调api时会先经过该模块,判断签名,是否过期,是否在白名单内等条件,并返回其他模块所需的api信息
- func ManagementCheckApi(ctx context.Context, req *apis.ManagementCheckApiReq, reply *apis.ManagementCheckApiReply) (err error) {
- o := orm.NewOrm()
- // 处理异常
- defer func() {
- if r := recover(); r != nil {
- err = errors.ServiceError
- l.Error("fatal",
- zap.String("func", "ManagementCheckApi"),
- zap.String("error", fmt.Sprintf("%v", r)))
- replaceMerchantId(req, reply)
- return
- }
- if err != nil {
- replaceMerchantId(req, reply)
- return
- }
- if reply.MerchantApiInfo.BaseApiId == 0 {
- reply.MerchantApiInfo.BaseApiId, _, _, _ = getBaseApiId(o, req)
- if reply.MerchantApiInfo.BaseApiId == 0 {
- err = jsonrpc2.NewJsonError(20005, "api信息获取异常")
- }
- if reply.MerchantApiInfo.MerchantId == 0 {
- err = jsonrpc2.NewJsonError(20005, "商户信息获取异常")
- }
- }
- if replaceKey, _ := req.Header["replace_app_key"]; replaceKey != "" &&
- (reply.MerchantApiInfo.ReplaceInfo.ReplaceMerchantChildApiId == 0 ||
- reply.MerchantApiInfo.ReplaceInfo.ReplaceMerchantDataApiId == 0 ||
- reply.MerchantApiInfo.ReplaceInfo.ReplaceMerchantId == 0 ||
- reply.MerchantApiInfo.ReplaceInfo.ReplaceBaseApiId == 0) {
- err = jsonrpc2.NewJsonError(20005, "内部商户信息获取异常")
- }
- }()
- reply.MerchantApiInfo.DecryptParam = req.RequestParam
- appKey, ok := req.Header["app_key"]
- if ok == false || appKey == "" {
- return errors.ArgsError
- }
- // 跑批内部商户appkey
- replaceAppKey, _ := req.Header["replace_app_key"]
- // 获取商户信息
- minfo, err := getMerchantInfo(o, appKey)
- if err != nil {
- return err
- }
- if replaceAppKey != "" && replaceAppKey != config.Conf.GdInnerAccount {
- return jsonrpc2.NewJsonError(20005, "内部账户不匹配")
- }
- // 获取内部商户信息
- rminfo, err := getMerchantInfo(o, replaceAppKey)
- if err != nil {
- return err
- }
- reply.MerchantApiInfo.MerchantId = minfo.Id
- reply.MerchantApiInfo.IsHttpCode = minfo.IsHttpCode
- //IP白名单验证
- if minfo.IpWhitelist != "" && replaceAppKey == "" && checkIpWhite(minfo.IpWhitelist, req.Ip) == false {
- return errors.IpAddrErr
- }
- // 签名验证
- reply.MerchantApiInfo.AppSecret = minfo.AppSecret
- err = signCheck(req, minfo.AppSecret, appKey)
- if err != nil {
- return err
- }
- // TODO 限流影响扣次
- // 获取并发请求token
- /*err, token := limit.Allow(req.Router, appKey)
- if err != nil {
- return err
- }
- reply.MerchantApiInfo.Token = *token*/
- // 根据原商户获取检查结果或根据内部商户获取检查结果
- if rminfo == nil {
- if minfo.AuthStatus == 0 {
- // 未认证
- return errors.NotAuthError
- } else if minfo.AuthStatus == 2 {
- // 认证不通过
- return errors.AuthFailError
- }
- err = getResultInfos(o, req, reply, minfo, true, appKey)
- } else {
- err = getReplaceResultInfos(o, req, reply, minfo, rminfo, true)
- }
- reply.MerchantApiInfo.IsHttpCode = minfo.IsHttpCode
- // 商户不存在,尝试非缓存读取信息进行检查
- if err != nil {
- if err == errors.CheckApiInfoNotExist {
- minfo, err = getMerchantInfoFromMysql(o, appKey)
- if err != nil {
- return err
- }
- rminfo, err = getMerchantInfoFromMysql(o, replaceAppKey)
- if err != nil {
- return err
- }
- if rminfo == nil {
- if minfo.AuthStatus == 0 {
- // 未认证
- return errors.NotAuthError
- } else if minfo.AuthStatus == 2 {
- // 认证不通过
- return errors.AuthFailError
- }
- err = getResultInfos(o, req, reply, minfo, false, appKey)
- } else {
- err = getReplaceResultInfos(o, req, reply, minfo, rminfo, false)
- }
- if err != nil {
- return err
- }
- } else {
- return err
- }
- }
- // TODO 限流影响扣次
- // 获取并发请求token
- /*err, token := limit.Allow(req.Router, appKey)
- if err != nil {
- return err
- }*/
- //reply.MerchantApiInfo.Token = *token
- l.Debug(utils.MarshalJsonString(req, reply))
- return nil
- }
- // LoadRedis 从redis中加载api、商户信息
- func LoadRedis() {
- o := orm.NewOrm()
- apiTabs := []apis.TGdApi{}
- merchantTabs := []apis.TGdMerchants{}
- o.QueryTable("t_gd_api").All(&apiTabs)
- o.QueryTable("t_gd_merchants").All(&merchantTabs)
- for _, v := range apiTabs {
- tmp := v
- utils.RedisSet("t_gd_api", v.Method+"-"+v.Router, tmp)
- }
- for _, v := range merchantTabs {
- tmp := v
- utils.RedisSet("t_gd_merchants", v.AppKey, tmp)
- }
- }
- var filterRuleMap = map[int64]apis.FilterRule{}
- // GetFilterRule 获取参数过滤规则
- func GetFilterRule() {
- o := orm.NewOrm()
- tabs := []apis.FilterRule{}
- o.Raw("select * from t_gd_filter_rule").QueryRows(&tabs)
- for _, v := range tabs {
- filterRuleMap[v.RuleId] = v
- }
- }
|