From 6dec851204dedd952abd6d252ca3518a20ee3a96 Mon Sep 17 00:00:00 2001 From: lbw-t14p Date: Sun, 18 Jan 2026 16:29:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B7=A5=E5=8D=95=E5=BC=80=E6=94=BE?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=92=8C=E6=9F=A5=E8=AF=A2=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 工单新增业务编号幂等处理,便于和业务系统结合使用 --- .gitignore | 1 + apis/process/workOrder.go | 10 +- config/db.sql | 2 + config/ferry.sql | 1 + config/settings.dev.yml | 11 ++ config/settings.yml | 15 ++- middleware/open_auth.go | 177 ++++++++++++++++++++++++++++++++ middleware/permission.go | 4 +- models/process/workOrder.go | 1 + pkg/notify/dingtalk/dingtalk.go | 25 ++--- pkg/redis/redis.go | 74 +++++++++++++ pkg/service/createWorkOrder.go | 37 ++++++- router/open/open_router.go | 18 ++++ router/router.go | 5 + tools/config/config.go | 16 +++ tools/config/open_auth.go | 43 ++++++++ tools/config/redis.go | 23 +++++ tools/string.go | 18 +++- 18 files changed, 452 insertions(+), 29 deletions(-) create mode 100644 middleware/open_auth.go create mode 100644 pkg/redis/redis.go create mode 100644 router/open/open_router.go create mode 100644 tools/config/open_auth.go create mode 100644 tools/config/redis.go diff --git a/.gitignore b/.gitignore index c4b8c0cb..4da44c42 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ temp/ vendor tmp/ config/settings.dev.yml +config/settings.local.yml logs mysql/data redis/data diff --git a/apis/process/workOrder.go b/apis/process/workOrder.go index 0527d54f..471e03ec 100644 --- a/apis/process/workOrder.go +++ b/apis/process/workOrder.go @@ -56,14 +56,16 @@ func ProcessStructure(c *gin.Context) { // 新建工单 func CreateWorkOrder(c *gin.Context) { - - err := service.CreateWorkOrder(c) + workOrderInfo, err := service.CreateWorkOrder(c) if err != nil { - app.Error(c, -1, err, "") + app.Error(c, -1, err, "提交工单申请失败") return } - app.OK(c, "", "成功提交工单申请") + app.OK(c, map[string]interface{}{ + "id": workOrderInfo.Id, + "biz_no": workOrderInfo.BizNo, + }, "提交工单申请成功") } // 工单列表 diff --git a/config/db.sql b/config/db.sql index a29f95c7..9ceb48b8 100644 --- a/config/db.sql +++ b/config/db.sql @@ -73,6 +73,8 @@ INSERT INTO `casbin_rule`(`p_type`, `v0`, `v1`, `v2`, `v3`, `v4`, `v5`) VALUES ( INSERT INTO `casbin_rule`(`p_type`, `v0`, `v1`, `v2`, `v3`, `v4`, `v5`) VALUES ('p', 'admin', '/api/v1/work-order/list', 'GET', NULL, NULL, NULL); INSERT INTO `casbin_rule`(`p_type`, `v0`, `v1`, `v2`, `v3`, `v4`, `v5`) VALUES ('p', 'admin', '/api/v1/work-order/unity', 'GET', NULL, NULL, NULL); INSERT INTO `casbin_rule`(`p_type`, `v0`, `v1`, `v2`, `v3`, `v4`, `v5`) VALUES ('p', 'admin', '/api/v1/work-order/inversion', 'POST', NULL, NULL, NULL); +INSERT INTO `casbin_rule`(`p_type`, `v0`, `v1`, `v2`, `v3`, `v4`, `v5`) VALUES ('p', 'admin', '/api/open/work-order/create', 'POST', NULL, NULL, NULL); +INSERT INTO `casbin_rule`(`p_type`, `v0`, `v1`, `v2`, `v3`, `v4`, `v5`) VALUES ('p', 'admin', '/api/open/work-order/process-structure', 'GET', NULL, NULL, NULL); INSERT INTO `casbin_rule`(`p_type`, `v0`, `v1`, `v2`, `v3`, `v4`, `v5`) VALUES ('p', 'admin', '/api/v1/dashboard', 'GET', NULL, NULL, NULL); INSERT INTO `casbin_rule`(`p_type`, `v0`, `v1`, `v2`, `v3`, `v4`, `v5`) VALUES ('p', 'admin', '/api/v1/work-order/urge', 'GET', NULL, NULL, NULL); INSERT INTO `casbin_rule`(`p_type`, `v0`, `v1`, `v2`, `v3`, `v4`, `v5`) VALUES ('p', 'admin', '/api/v1/settings', 'POST', NULL, NULL, NULL); diff --git a/config/ferry.sql b/config/ferry.sql index 82619de7..66dcd84c 100644 --- a/config/ferry.sql +++ b/config/ferry.sql @@ -164,6 +164,7 @@ CREATE TABLE `p_work_order_info` ( `title` varchar(128) DEFAULT NULL, `priority` int DEFAULT NULL, `process` int DEFAULT NULL, + `biz_no` varchar(128) DEFAULT NULL, `classify` int DEFAULT NULL, `is_end` int DEFAULT '0', `is_denied` int DEFAULT '0', diff --git a/config/settings.dev.yml b/config/settings.dev.yml index 9789c2e8..c0b2eb02 100644 --- a/config/settings.dev.yml +++ b/config/settings.dev.yml @@ -57,10 +57,21 @@ settings: maxbackups: 300 maxsize: 10240 path: ./logs/ferry.log + openauth: + clients: + ferry: + identitykey: 1 + rolekey: admin + secret: test2026 + nonceexpiretime: 600 + timeout: 300 public: islocation: 0 redis: url: redis://:123456@192.168.31.94:6379 + addr: 192.168.31.94:6379 + db: 0 + pwd: "123456" ssl: key: keystring pem: temp/pem.pem diff --git a/config/settings.yml b/config/settings.yml index 07f997c7..265b8e37 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -17,6 +17,11 @@ settings: password: 123456 port: 3306 username: root + redis: + url: redis://ferry_redis:6379 + addr: ferry_redis:6379 + db: 0 + pwd: "" dingtalk: agentid: 1234567890 appkey: your dingtalk appkey @@ -59,8 +64,14 @@ settings: path: ./logs/ferry.log public: islocation: 0 - redis: - url: redis://ferry_redis:6379 ssl: key: keystring pem: temp/pem.pem + openauth: + appkeys: + ferry: + secret: 123456 + identityKey: 1 + roleKey: admin + nonceexpiretime: 600 + timeout: 300 diff --git a/middleware/open_auth.go b/middleware/open_auth.go new file mode 100644 index 00000000..f648b044 --- /dev/null +++ b/middleware/open_auth.go @@ -0,0 +1,177 @@ +package middleware + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + jwt "ferry/pkg/jwtauth" + "ferry/pkg/logger" + "ferry/pkg/redis" + "ferry/tools" + "ferry/tools/config" + "net/http" + "strconv" + "strings" + "time" + + "github.com/gin-gonic/gin" +) + +// OpenAuth API认证中间件 +func OpenAuth() gin.HandlerFunc { + return func(c *gin.Context) { + // 1. 从请求中获取认证参数 - 使用更合适的命名 + appKey := c.Request.Header.Get("X-App-Key") + signature := c.Request.Header.Get("X-Signature") + timestampStr := c.Request.Header.Get("X-Timestamp") + nonce := c.Request.Header.Get("X-Nonce") + + // 2. 验证参数是否完整 + if appKey == "" || signature == "" || timestampStr == "" || nonce == "" { + c.JSON(http.StatusUnauthorized, gin.H{ + "code": 401, + "msg": "缺少必要的认证参数", + }) + c.Abort() + return + } + + // 3. 验证时间戳是否有效 + timestamp, err := strconv.ParseInt(timestampStr, 10, 64) + if err != nil { + c.JSON(http.StatusUnauthorized, gin.H{ + "code": 401, + "msg": "无效的时间戳格式", + }) + c.Abort() + return + } + + currentTime := time.Now().Unix() + if currentTime-timestamp > config.OpenAuthConfig.Timeout || timestamp-currentTime > config.OpenAuthConfig.Timeout { + c.JSON(http.StatusUnauthorized, gin.H{ + "code": 401, + "msg": "时间戳已过期或无效", + }) + c.Abort() + return + } + + // 4. 验证nonce是否已被使用 + exists, err := checkNonce(nonce) + if err != nil { + logger.Error(err) + c.JSON(http.StatusInternalServerError, gin.H{ + "code": 500, + "msg": "验证nonce失败", + }) + c.Abort() + return + } + + if exists { + c.JSON(http.StatusUnauthorized, gin.H{ + "code": 401, + "msg": "nonce已被使用", + }) + c.Abort() + return + } + + // 记录nonce到Redis,设置过期时间 + expireTime := time.Duration(config.OpenAuthConfig.NonceExpireTime) * time.Second + err = setNonce(nonce, expireTime) + if err != nil { + logger.Error(err) + c.JSON(http.StatusInternalServerError, gin.H{ + "code": 500, + "msg": "存储nonce失败", + }) + c.Abort() + return + } + + // 5. 从配置中获取AppSecret + appConfig, exists := config.OpenAuthConfig.Clients[appKey] + if !exists || appConfig == nil || appConfig.Secret == "" || appConfig.IdentityKey == 0 || appConfig.RoleKey == "" { + c.JSON(http.StatusUnauthorized, gin.H{ + "code": 401, + "msg": "无效的AppKey", + }) + c.Abort() + return + } + + // 6. 验证签名是否正确 + validSign, err := generateSign(appKey, appConfig.Secret, timestampStr, nonce, c) + if err != nil { + logger.Error(err) + c.JSON(http.StatusInternalServerError, gin.H{ + "code": 500, + "msg": "生成签名失败", + }) + c.Abort() + return + } + + if signature != validSign { + c.JSON(http.StatusUnauthorized, gin.H{ + "code": 401, + "msg": "无效的签名", + }) + c.Abort() + return + } + //设置用户ID + claims := jwt.MapClaims{ + jwt.IdentityKey: float64(appConfig.IdentityKey), + jwt.RoleKey: appConfig.RoleKey, + } + c.Set("JWT_PAYLOAD", claims) + // 认证通过,继续处理请求 + c.Next() + } +} + +// 签名算法:HMAC-SHA256(AppSecret, AppKey + timestamp + nonce + requestBody) +func generateSign(appKey, appSecret, timestamp, nonce string, c *gin.Context) (string, error) { + // 获取请求体 + body, err := tools.GetBodyString2(c) + if err != nil { + return "", err + } + + // 组合签名字符串 + // 按照字典序排序参数 + params := []string{appKey, timestamp, nonce, body} + //sort.Strings(params) + signStr := strings.Join(params, "") + + // 使用HMAC-SHA256算法生成签名 + hmacHash := hmac.New(sha256.New, []byte(appSecret)) + _, err = hmacHash.Write([]byte(signStr)) + if err != nil { + return "", err + } + + // 将签名转换为十六进制字符串 + signature := hex.EncodeToString(hmacHash.Sum(nil)) + + return signature, nil +} + +// setNonce 将nonce存储到Redis中 +func setNonce(nonce string, expireTime time.Duration) error { + key := "workorder:openauth:nonce:" + nonce + return redis.GetClient().Set(key, time.Now().Unix(), expireTime).Err() +} + +// checkNonce 检查nonce是否已存在 +func checkNonce(nonce string) (bool, error) { + key := "workorder:openauth:nonce:" + nonce + exists, err := redis.GetClient().Exists(key).Result() + if err != nil { + return false, err + } + return exists > 0, nil +} diff --git a/middleware/permission.go b/middleware/permission.go index f6d1e95b..d46a1895 100644 --- a/middleware/permission.go +++ b/middleware/permission.go @@ -12,7 +12,7 @@ import ( "github.com/gin-gonic/gin" ) -//权限检查中间件 +// 权限检查中间件 func AuthCheckRole() gin.HandlerFunc { return func(c *gin.Context) { data, _ := c.Get("JWT_PAYLOAD") @@ -21,7 +21,7 @@ func AuthCheckRole() gin.HandlerFunc { tools.HasError(err, "", 500) //检查权限 res, err := e.Enforce(v["rolekey"], c.Request.URL.Path, c.Request.Method) - logger.Info(v["rolekey"], c.Request.URL.Path, c.Request.Method) + logger.Info(v["rolekey"], c.Request.URL.Path, " ", c.Request.Method) tools.HasError(err, "", 500) if res { diff --git a/models/process/workOrder.go b/models/process/workOrder.go index 3aa6e2cf..c0e5e66f 100644 --- a/models/process/workOrder.go +++ b/models/process/workOrder.go @@ -15,6 +15,7 @@ type WorkOrderInfo struct { Title string `gorm:"column:title; type:varchar(128)" json:"title" form:"title"` // 工单标题 Priority int `gorm:"column:priority; type:int(11)" json:"priority" form:"priority"` // 工单优先级 1,正常 2,紧急 3,非常紧急 Process int `gorm:"column:process; type:int(11)" json:"process" form:"process"` // 流程ID + BizNo string `gorm:"column:biz_no; type:varchar(128)" json:"biz_no" form:"biz_no"` // 业务ID Classify int `gorm:"column:classify; type:int(11)" json:"classify" form:"classify"` // 分类ID IsEnd int `gorm:"column:is_end; type:int(11); default:0" json:"is_end" form:"is_end"` // 是否结束, 0 未结束,1 已结束 IsDenied int `gorm:"column:is_denied; type:int(11); default:0" json:"is_denied" form:"is_denied"` // 是否被拒绝, 0 没有,1 有 diff --git a/pkg/notify/dingtalk/dingtalk.go b/pkg/notify/dingtalk/dingtalk.go index 407d9628..2c798cbb 100644 --- a/pkg/notify/dingtalk/dingtalk.go +++ b/pkg/notify/dingtalk/dingtalk.go @@ -9,20 +9,20 @@ package dingtalk import ( "bytes" "encoding/json" + "ferry/pkg/logger" + "ferry/pkg/redis" "fmt" "io/ioutil" "net/http" "strings" "time" - "ferry/pkg/logger" - "github.com/go-redis/redis" "github.com/spf13/viper" ) // var appKey = viper.GetString("settings.dingtalk.appkey") -// var appSecret = viper.GetString("settings.dingtalk.appsecret") -// var agentId = viper.GetInt64("settings.dingtalk.agentid") +// var appSecret = viper.GetString("settings.dingtalk.appsecret") +// var agentId = viper.GetInt64("settings.dingtalk.agentid") const ( GetAccessTokenUrl = "https://oapi.dingtalk.com/gettoken" @@ -140,23 +140,18 @@ func SendFlowMsg(token string, content SendFlowMsgBody) error { } func SendDingMsg(phoneList []string, url string, msgTitle string, msgCreator string, priority string, createdAt string) { - appKey := viper.GetString("settings.dingtalk.appkey") - appSecret := viper.GetString("settings.dingtalk.appsecret") - agentId := viper.GetInt64("settings.dingtalk.agentid") - - client := redis.NewClient(&redis.Options{ - Addr: viper.GetString("settings.redis.host"), - Password: viper.GetString("settings.redis.pwd"), - DB: 1, // use default DB - }) + appKey := viper.GetString("settings.dingtalk.appkey") + appSecret := viper.GetString("settings.dingtalk.appsecret") + agentId := viper.GetInt64("settings.dingtalk.agentid") + client := redis.GetClient() var token string - tokenByte, err := client.Get("accessTokenDingtalk").Result() + tokenByte, err := client.Get("workorder:accessTokenDingtalk").Result() if err != nil { logger.Info(err) token = GetAccessToken(appKey, appSecret) - err = client.Set("accessTokenDingtalk", token, 120*time.Minute).Err() + err = client.Set("workorder:accessTokenDingtalk", token, 120*time.Minute).Err() if err != nil { logger.Info(err) } diff --git a/pkg/redis/redis.go b/pkg/redis/redis.go new file mode 100644 index 00000000..03a44ec2 --- /dev/null +++ b/pkg/redis/redis.go @@ -0,0 +1,74 @@ +package redis + +import ( + "ferry/tools/config" + "time" + + "github.com/go-redis/redis" + "github.com/go-redsync/redsync/v4" + "github.com/go-redsync/redsync/v4/redis/goredis" +) + +var ( + Client *redis.Client + Redsync *redsync.Redsync +) + +// InitRedis 初始化Redis客户端 +func InitRedis() { + // 解析Redis配置 + addr := config.RedisConfig.Addr + pwd := config.RedisConfig.Pwd + db := config.RedisConfig.DB + + // 如果没有配置host,则从URL解析 + if addr == "" { + // 这里可以添加URL解析逻辑 + // 简化处理,直接使用默认配置 + addr = "localhost:6379" + } + + // 创建Redis客户端 + Client = redis.NewClient(&redis.Options{ + Addr: addr, + Password: pwd, + DB: db, + }) + + // 测试连接 + _, err := Client.Ping().Result() + if err != nil { + panic(err) + } + + // 创建Redsync实例 + pool := goredis.NewPool(Client) + Redsync = redsync.New(pool) +} + +// GetClient 获取Redis客户端 +func GetClient() *redis.Client { + if Client == nil { + InitRedis() + } + return Client +} + +// GetRedsync 获取Redsync实例 +func GetRedsync() *redsync.Redsync { + if Redsync == nil { + InitRedis() + } + return Redsync +} + +// Lock 分布式锁接口 +type Lock interface { + Lock() error + Unlock() (bool, error) +} + +// NewLock 创建分布式锁 +func NewLock(key string, expiry time.Duration) Lock { + return GetRedsync().NewMutex(key, redsync.WithExpiry(expiry)) +} diff --git a/pkg/service/createWorkOrder.go b/pkg/service/createWorkOrder.go index a572989e..aea38823 100644 --- a/pkg/service/createWorkOrder.go +++ b/pkg/service/createWorkOrder.go @@ -7,6 +7,7 @@ import ( "ferry/models/process" "ferry/models/system" "ferry/pkg/notify" + "ferry/pkg/redis" "ferry/tools" "fmt" "time" @@ -18,7 +19,7 @@ import ( @Author : lanyulei */ -func CreateWorkOrder(c *gin.Context) (err error) { +func CreateWorkOrder(c *gin.Context) (workOrderInfo process.WorkOrderInfo, err error) { var ( taskList []string stateList []interface{} @@ -55,6 +56,35 @@ func CreateWorkOrder(c *gin.Context) (err error) { return } + // 幂等检查:如果传入了bizNo,则检查是否已存在该bizNo的工单 + if workOrderValue.BizNo != "" { + // 创建分布式锁,防止同一bizNo重复提交 + lockKey := fmt.Sprintf("workorder:lock:%d:%s", workOrderValue.Process, workOrderValue.BizNo) + lock := redis.NewLock(lockKey, 5*time.Second) + // 尝试获取锁 + err = lock.Lock() + if err != nil { + err = fmt.Errorf("当前工单申请正在处理中,请稍后重试") + return + } + // 确保锁被释放 + defer func() { + _, _ = lock.Unlock() + }() + + var existingWorkOrder process.WorkOrderInfo + err = orm.Eloquent.Model(&existingWorkOrder).Where("process = ? AND biz_no = ?", workOrderValue.Process, workOrderValue.BizNo).Find(&existingWorkOrder).Error + if err != nil { + err = fmt.Errorf("查询工单失败,%v", err.Error()) + return + } + // 如果存在该bizNo的工单,则直接返回已有结果 + if existingWorkOrder.Id != 0 { + workOrderInfo = existingWorkOrder + return + } + } + relatedPerson, err := json.Marshal([]int{tools.GetUserId(c)}) if err != nil { return @@ -177,7 +207,7 @@ func CreateWorkOrder(c *gin.Context) (err error) { for _, edge := range sourceEdges { targetStateValue, err := processState.GetNode(edge["target"].(string)) if err != nil { - return err + return workOrderInfo, err } variableValue = append(variableValue, map[string]interface{}{ "id": edge["target"].(string), @@ -203,12 +233,13 @@ func CreateWorkOrder(c *gin.Context) (err error) { return } - var workOrderInfo = process.WorkOrderInfo{ + workOrderInfo = process.WorkOrderInfo{ Title: workOrderValue.Title, Priority: workOrderValue.Priority, Process: workOrderValue.Process, Classify: workOrderValue.Classify, State: workOrderValue.State, + BizNo: workOrderValue.BizNo, RelatedPerson: relatedPerson, Creator: tools.GetUserId(c), } diff --git a/router/open/open_router.go b/router/open/open_router.go new file mode 100644 index 00000000..4c6bae16 --- /dev/null +++ b/router/open/open_router.go @@ -0,0 +1,18 @@ +package open + +import ( + "ferry/apis/process" + "ferry/middleware" + + "github.com/gin-gonic/gin" +) + +// 注册公共路由 +func RegisterOpenRouter(v1 *gin.RouterGroup) { + p := v1.Group("/work-order").Use(middleware.OpenAuth()).Use(middleware.AuthCheckRole()) + { + // 注册开放接口创建工单路由 + p.POST("/create", process.CreateWorkOrder) + p.GET("/process-structure", process.ProcessStructure) + } +} diff --git a/router/router.go b/router/router.go index 822f7f66..994cbf1c 100644 --- a/router/router.go +++ b/router/router.go @@ -4,6 +4,7 @@ import ( "ferry/apis/tpl" "ferry/pkg/jwtauth" "ferry/router/dashboard" + "ferry/router/open" "ferry/router/process" systemRouter "ferry/router/system" @@ -71,4 +72,8 @@ func sysCheckRoleRouterInit(r *gin.RouterGroup, authMiddleware *jwtauth.GinJWTMi process.RegisterTaskRouter(v1, authMiddleware) process.RegisterTplRouter(v1, authMiddleware) process.RegisterWorkOrderRouter(v1, authMiddleware) + + //开放接口 + openV1 := r.Group("/api/open") + open.RegisterOpenRouter(openV1) } diff --git a/tools/config/config.go b/tools/config/config.go index 3fbad696..5b03f839 100644 --- a/tools/config/config.go +++ b/tools/config/config.go @@ -10,9 +10,11 @@ import ( ) var cfgDatabase *viper.Viper +var cfgRedis *viper.Viper var cfgApplication *viper.Viper var cfgJwt *viper.Viper var cfgSsl *viper.Viper +var cfgOpenAuth *viper.Viper // ConfigSetup 载入配置文件 func ConfigSetup(path string) { @@ -35,6 +37,13 @@ func ConfigSetup(path string) { } DatabaseConfig = InitDatabase(cfgDatabase) + // Redis初始化 + cfgRedis = viper.Sub("settings.redis") + if cfgRedis == nil { + panic("config not found settings.redis") + } + RedisConfig = InitRedis(cfgRedis) + // 启动参数 cfgApplication = viper.Sub("settings.application") if cfgApplication == nil { @@ -56,6 +65,13 @@ func ConfigSetup(path string) { } SslConfig = InitSsl(cfgSsl) + // OpenAuth初始化 + cfgOpenAuth = viper.Sub("settings.openauth") + if cfgOpenAuth == nil { + panic("config not found settings.openauth") + } + OpenAuthConfig = InitOpenAuth(cfgOpenAuth) + // 日志配置 logger.Init() } diff --git a/tools/config/open_auth.go b/tools/config/open_auth.go new file mode 100644 index 00000000..ea87f458 --- /dev/null +++ b/tools/config/open_auth.go @@ -0,0 +1,43 @@ +package config + +import "github.com/spf13/viper" + +// ClientConfig 应用密钥配置 +type ClientConfig struct { + Secret string `mapstructure:"secret"` + IdentityKey int `mapstructure:"identityKey"` + RoleKey string `mapstructure:"roleKey"` +} + +// OpenAuth 开放认证配置 +type OpenAuth struct { + Clients map[string]*ClientConfig `mapstructure:"clients"` + Timeout int64 `mapstructure:"timeout"` + NonceExpireTime int64 `mapstructure:"nonceexpiretime"` +} + +// InitOpenAuth 初始化开放认证配置 +func InitOpenAuth(cfg *viper.Viper) *OpenAuth { + openAuth := &OpenAuth{ + Clients: make(map[string]*ClientConfig), + Timeout: cfg.GetInt64("timeout"), + NonceExpireTime: cfg.GetInt64("nonceexpiretime"), + } + + // 获取所有的appkey配置 + appKeys := cfg.GetStringMap("clients") + for appKey, config := range appKeys { + if configMap, ok := config.(map[string]interface{}); ok { + appKeyConfig := &ClientConfig{ + Secret: configMap["secret"].(string), + IdentityKey: configMap["identitykey"].(int), + RoleKey: configMap["rolekey"].(string), + } + openAuth.Clients[appKey] = appKeyConfig + } + } + + return openAuth +} + +var OpenAuthConfig = new(OpenAuth) diff --git a/tools/config/redis.go b/tools/config/redis.go new file mode 100644 index 00000000..2373cdfe --- /dev/null +++ b/tools/config/redis.go @@ -0,0 +1,23 @@ +package config + +import ( + "github.com/spf13/viper" +) + +type Redis struct { + Addr string + Host string + Pwd string + DB int +} + +func InitRedis(cfg *viper.Viper) *Redis { + return &Redis{ + Addr: cfg.GetString("addr"), + Host: cfg.GetString("host"), + Pwd: cfg.GetString("pwd"), + DB: cfg.GetInt("db"), + } +} + +var RedisConfig = new(Redis) diff --git a/tools/string.go b/tools/string.go index 0269e747..e466e602 100644 --- a/tools/string.go +++ b/tools/string.go @@ -1,12 +1,14 @@ package tools import ( + "bytes" "encoding/json" "fmt" - "github.com/gin-gonic/gin" "io/ioutil" "strconv" "time" + + "github.com/gin-gonic/gin" ) func StringToInt64(e string) (int64, error) { @@ -17,7 +19,6 @@ func StringToInt(e string) (int, error) { return strconv.Atoi(e) } - func GetCurrntTimeStr() string { return time.Now().Format("2006/01/02 15:04:05") } @@ -26,7 +27,6 @@ func GetCurrntTime() time.Time { return time.Now() } - func StructToJsonStr(e interface{}) (string, error) { if b, err := json.Marshal(e); err == nil { return string(b), err @@ -45,6 +45,18 @@ func GetBodyString(c *gin.Context) (string, error) { } } +func GetBodyString2(c *gin.Context) (string, error) { + body, err := ioutil.ReadAll(c.Request.Body) + if err != nil { + fmt.Printf("read body err, %v\n", err) + return "", err + } + // 重置请求体,以便后续处理程序可以再次读取 + rc := ioutil.NopCloser(bytes.NewBuffer(body)) + c.Request.Body = rc + return string(body), nil +} + func JsonStrToMap(e string) (map[string]interface{}, error) { var dict map[string]interface{} if err := json.Unmarshal([]byte(e), &dict); err == nil {