- 新增CamelOilToken和CamelOilCardBinding数据库表,实现Token及卡密绑定记录管理 - 在service层增加Token的创建、查询、更新、删除及分页功能 - 实现卡密与Token绑定的业务逻辑,支持基于Token的卡密管理 - 在API层新增Token和卡密绑定相关接口:创建Token、获取Token详情、删除Token、列出Token及根据Token查询绑定卡密 - camel_oil_api新增绑卡接口,支持绑卡状态分类及错误处理 - 在定时任务中增加卡密绑定任务,实现自动处理已支付订单的卡密绑定 - 优化订单提交及支付流程,包含日志调整和请求参数随机扰动 - 统一调整camel_oil模块多控制器实现,完成账号状态查询及订单相关接口实现 - 注册更多camel_oil定时任务,包括订单支付检查、账号日重置和待回调订单处理任务
167 lines
5.0 KiB
Go
167 lines
5.0 KiB
Go
package middleware
|
||
|
||
import (
|
||
"net"
|
||
"slices"
|
||
"time"
|
||
|
||
"github.com/duke-git/lancet/v2/netutil"
|
||
"github.com/gogf/gf/v2/encoding/gjson"
|
||
|
||
"kami/internal/errHandler"
|
||
"kami/internal/service"
|
||
|
||
"github.com/gogf/gf/v2/container/gset"
|
||
"github.com/gogf/gf/v2/errors/gcode"
|
||
|
||
"github.com/gogf/gf/v2/net/ghttp"
|
||
"github.com/gogf/gf/v2/os/glog"
|
||
"github.com/gogf/gf/v2/text/gstr"
|
||
|
||
"kami/utility/token"
|
||
"kami/utility/verify"
|
||
)
|
||
|
||
// whiteListAuth 白名单中间件
|
||
func whiteListAuth(r *ghttp.Request) gcode.Code {
|
||
whiteList := []string{
|
||
"/api/merchant/order/query",
|
||
"/api/restriction/block/order",
|
||
"/api/restriction/location/checkIPAllowed",
|
||
"/api/cardInfo/appleCard/submit",
|
||
"/api/cardInfo/appleCard/rechargeOrder/handler",
|
||
"/api/cardInfo/appleCard/query",
|
||
"/api/cardInfo/walmart/account/load",
|
||
"/api/cardInfo/appleCard/rechargeOrder/callback",
|
||
"/api/recharge/tMallGame/agiso/callback",
|
||
"/api/recharge/tMallGame/account/getOneByRandom",
|
||
"/api/recharge/tMallGame/order/submit",
|
||
"/api/recharge/tMallGame/account/auth/callback",
|
||
"/api/recharge/tMallGame/data/sync",
|
||
"/api/recharge/tMallGame/order/queryOne",
|
||
"/api/cardInfo/JDCard/order/submit",
|
||
"/api/cardInfo/walmart/order/submit",
|
||
"/api/cardInfo/cTrip/order/submit",
|
||
"/api/restriction/collection/userInfo",
|
||
"/api/restriction/collection/userInfo",
|
||
"/api/cookieInfo/jd/order/placeOrder",
|
||
"/api/jd-cookie/order/create",
|
||
"/api/jd-v2/order/submit",
|
||
}
|
||
internalWhiteListAuth := []string{
|
||
"/api/aes/encryption/params",
|
||
}
|
||
// 判断 ip
|
||
if slices.Contains(internalWhiteListAuth, r.URL.Path) && netutil.IsInternalIP(net.ParseIP(r.GetClientIp())) {
|
||
return gcode.CodeOK
|
||
}
|
||
|
||
whiteSet := gset.NewStrSet(true)
|
||
whiteSet.Add(whiteList...)
|
||
if whiteSet.Contains(r.URL.Path) {
|
||
return gcode.CodeOK
|
||
}
|
||
return gcode.CodeNotAuthorized
|
||
}
|
||
|
||
func loginAuth(r *ghttp.Request) gcode.Code {
|
||
// 获取Token
|
||
tokenStr := token.GetRequestToken(r)
|
||
if tokenStr == "" {
|
||
return gcode.New(errHandler.ErrTokenError.Code(), "获取Token失败", nil)
|
||
}
|
||
userToken, err := token.ParseUserToken(r.GetCtx(), tokenStr)
|
||
if err != nil {
|
||
glog.Error(r.GetCtx(), "校验Token失败,当前Token", tokenStr, "错误码:", err)
|
||
return gcode.New(errHandler.ErrTokenError.Code(), "校验Token失败", nil)
|
||
}
|
||
// 查看redis中是否有token
|
||
oldTokenStr, err := token.GetTokenFromRedis(r.GetCtx(), userToken.UserID, userToken.ID)
|
||
if err != nil {
|
||
glog.Error(r.GetCtx(), "校验Token失败", err)
|
||
return gcode.New(errHandler.ErrTokenError.Code(), "校验Token失败", nil)
|
||
}
|
||
if oldTokenStr != tokenStr {
|
||
glog.Error(r.GetCtx(), "校验Token失败", err)
|
||
return gcode.New(errHandler.ErrTokenError.Code(), "当前Token失效", nil)
|
||
}
|
||
// 续签token
|
||
newToken, err := token.RefreshUserToken(r.GetCtx(), *userToken)
|
||
if err != nil {
|
||
glog.Error(r.GetCtx(), "续签Token失败", err)
|
||
return gcode.New(errHandler.ErrTokenError.Code(), "续签Token失败", nil)
|
||
}
|
||
if newToken != "" {
|
||
r.Response.Header().Set("refresh-token", newToken)
|
||
}
|
||
return gcode.CodeOK
|
||
}
|
||
|
||
func iFrameAuth(r *ghttp.Request) gcode.Code {
|
||
tokenStr := token.GetRequestToken(r)
|
||
if tokenStr == "" {
|
||
return gcode.New(errHandler.ErrTokenError.Code(), "Token不存在,请刷新页面!", nil)
|
||
}
|
||
ctx := r.GetCtx()
|
||
frontendModel, err := service.SysConfigDict().GetAESKeyBytes(ctx)
|
||
if err != nil {
|
||
return gcode.New(errHandler.ErrTokenError.Code(), "解析Token错误!", nil)
|
||
}
|
||
tokenByte, err := verify.AesCBCURLDecryptWithBase64(tokenStr, frontendModel.Key, frontendModel.IV)
|
||
if err != nil {
|
||
glog.Error(ctx, "解析Token错误", tokenStr, err)
|
||
return gcode.New(errHandler.ErrTokenError.Code(), "Token格式错误!", nil)
|
||
}
|
||
tokenStruct := struct {
|
||
CurrentTime int64 `json:"currentTime"`
|
||
UserId string `json:"userId"`
|
||
UserAuth string `json:"userAuth"`
|
||
}{}
|
||
if err = gjson.DecodeTo(tokenByte, &tokenStruct); err != nil {
|
||
glog.Error(ctx, "解析Token错误", tokenStr, err)
|
||
return gcode.New(errHandler.ErrTokenError.Code(), "Token格式错误!", nil)
|
||
}
|
||
if time.Since(time.Unix(tokenStruct.CurrentTime, 0)) > time.Minute*30 {
|
||
return gcode.New(errHandler.ErrTokenError.Code(), "token失效,请刷新页面!", nil)
|
||
}
|
||
return gcode.CodeOK
|
||
}
|
||
|
||
func LoginOrIframeAuth(r *ghttp.Request) {
|
||
if whiteListAuth(r) == gcode.CodeOK {
|
||
r.Middleware.Next()
|
||
return
|
||
}
|
||
tokenFrom := r.Request.Header.Get("tokenFrom")
|
||
if gstr.ToLower(tokenFrom) == "login" {
|
||
code := loginAuth(r)
|
||
if code != gcode.CodeOK {
|
||
r.Response.WriteJson(ghttp.DefaultHandlerResponse{
|
||
Code: code.Code(),
|
||
Message: code.Message(),
|
||
Data: code.Detail(),
|
||
})
|
||
return
|
||
}
|
||
r.Middleware.Next()
|
||
return
|
||
}
|
||
if gstr.ToLower(tokenFrom) == "iframe" {
|
||
code := iFrameAuth(r)
|
||
if code != gcode.CodeOK {
|
||
r.Response.WriteJson(ghttp.DefaultHandlerResponse{
|
||
Code: code.Code(),
|
||
Message: code.Message(),
|
||
Data: code.Detail(),
|
||
})
|
||
return
|
||
}
|
||
r.Middleware.Next()
|
||
return
|
||
}
|
||
r.Response.WriteJson(ghttp.DefaultHandlerResponse{
|
||
Code: errHandler.ErrTokenError.Code(),
|
||
Message: "token来源不明",
|
||
})
|
||
}
|