neo лет назад: 2
Родитель
Сommit
9d265a56bc
10 измененных файлов с 1611 добавлено и 5 удалено
  1. 14 0
      main.go
  2. 258 0
      nppa/interface.go
  3. 90 0
      nppa/interface_test.go
  4. 165 0
      nppa/realname.go
  5. 254 0
      nppa/recheck.go
  6. 155 0
      nppa/report.go
  7. 162 0
      nppa/test.go
  8. 317 0
      nppa/util.go
  9. 169 2
      utils/redis.go
  10. 27 3
      utils/util.go

+ 14 - 0
main.go

@@ -14,6 +14,7 @@ import (
14 14
 	"github.com/astaxie/beego"
15 15
 	"github.com/drone/routes"
16 16
 
17
+	"box-3rdServer/nppa"
17 18
 	"box-3rdServer/sensitive"
18 19
 	"box-3rdServer/utils"
19 20
 )
@@ -30,6 +31,19 @@ func main() {
30 31
 	mux.Post("/sensitive/checkword", sensitive.HttpCheckWord)
31 32
 	mux.Get("/sensitive/changeword", sensitive.HttpChangeWord)
32 33
 	mux.Post("/sensitive/changeword", sensitive.HttpChangeWord)
34
+	// 实名认证
35
+	if nppa.IsModule() {
36
+		nppa.Init()
37
+		mux.Get("/nppa/check_id", nppa.HttpCheckPlayerID)
38
+		mux.Post("/nppa/check_id", nppa.HttpCheckPlayerID)
39
+		mux.Get("/nppa/query_id", nppa.HttpQueryPlayerID)
40
+		mux.Post("/nppa/query_id", nppa.HttpQueryPlayerID)
41
+		mux.Get("/nppa/loginout", nppa.HttpLoginout)
42
+		mux.Post("/nppa/loginout", nppa.HttpLoginout)
43
+		mux.Get("/nppa/test_check_id", nppa.HttpTestCheckPlayerID)
44
+		mux.Get("/nppa/test_query_id", nppa.HttpTestQueryPlayerID)
45
+		mux.Get("/nppa/test_loginout", nppa.HttpTestLoginout)
46
+	}
33 47
 
34 48
 	http.Handle("/", mux)
35 49
 	http.ListenAndServe(":"+beego.AppConfig.String("httpport"), nil)

+ 258 - 0
nppa/interface.go

@@ -0,0 +1,258 @@
1
+/*
2
+ * @Descripttion:实名认证
3
+ * @version:
4
+ * @Author: Neo,Huang
5
+ * @Date: 2021-04-17 11:04:16
6
+ * @LastEditors: Neo,Huang
7
+ * @LastEditTime: 2022-07-06 14:32:44
8
+ */
9
+package nppa
10
+
11
+import (
12
+	"crypto/md5"
13
+	"encoding/hex"
14
+	"encoding/json"
15
+	"fmt"
16
+	"log"
17
+	"net/http"
18
+
19
+	"box-3rdServer/utils"
20
+)
21
+
22
+// 是否开启功能
23
+func IsModule() bool {
24
+	status := utils.StringToInt(utils.GetKeyConf("nppa", "status"))
25
+	return status > 0
26
+}
27
+
28
+// 初始化
29
+func Init() {
30
+	log.Println("nppa:Init")
31
+	initConf()
32
+
33
+	mapAidToConf.Range(func(k, v interface{}) bool {
34
+		aid := k.(int)
35
+		key := fmt.Sprintf(aidKey, aid)
36
+		for utils.Zcard(key) > 0 {
37
+			sendCollections(aid, key)
38
+		}
39
+		return true
40
+	})
41
+
42
+	ReportCollections()
43
+	// InitRecheckProc()
44
+}
45
+
46
+// 实名认证 - 校验
47
+// 方法:get/post
48
+// 参数:
49
+//
50
+//	uid:玩家ID
51
+//	channel:渠道
52
+//	name:实名-姓名
53
+//	idNum:实名-身份证ID
54
+//
55
+// 返回
56
+//
57
+//	true/false
58
+func HttpCheckPlayerID(w http.ResponseWriter, r *http.Request) {
59
+	req := r.URL.Query()
60
+	uid := utils.StringToInt(req.Get("uid"))
61
+	chn := utils.StringToInt(req.Get("channel"))
62
+	name := req.Get("name")
63
+	idNum := req.Get("idNum")
64
+
65
+	ret := CheckPlayerId(uid, chn, name, idNum)
66
+	log.Printf("玩家[%d] 实名认证结果[%d] msg[%s]", uid, utils.StringToInt(ret["status"]), ret["msg"])
67
+
68
+	pack, _ := json.Marshal(ret)
69
+	// 发送成功
70
+	w.Write(pack)
71
+}
72
+
73
+// 实名认证 - 查询
74
+// 方法:get/post
75
+// 参数:
76
+//
77
+//	uid:玩家ID
78
+//	channel:渠道
79
+//
80
+// 返回
81
+//
82
+//	ture/false
83
+func HttpQueryPlayerID(w http.ResponseWriter, r *http.Request) {
84
+	req := r.URL.Query()
85
+	uid := utils.StringToInt(req.Get("uid"))
86
+	chn := utils.StringToInt(req.Get("channel"))
87
+
88
+	ret := QueryPlayerId(uid, chn)
89
+
90
+	pack, _ := json.Marshal(ret)
91
+	// 发送成功
92
+	w.Write(pack)
93
+}
94
+
95
+// 实名认证 - 用户行为数据上报
96
+// 方法:get/post
97
+// 参数:
98
+//
99
+//	 channel:渠道
100
+//		si:游戏内部会话标识
101
+//	 bt:用户行为类型 0:下线 1:上线
102
+//	 ot:行为发生时间戳
103
+//	 ct:用户行为数据上报类型 0:已认证用户 2:游客
104
+//	 di:游客模式设备标识
105
+//	 pi:实名用户唯一标识
106
+func HttpLoginout(w http.ResponseWriter, r *http.Request) {
107
+	req := r.URL.Query()
108
+	channel := req.Get("channel")
109
+	si := req.Get("si")
110
+	bt := utils.StringToInt(req.Get("bt"))
111
+	ot := utils.StringToInt(req.Get("ot"))
112
+	ct := utils.StringToInt(req.Get("ct"))
113
+	di := req.Get("di")
114
+	pi := req.Get("pi")
115
+
116
+	ret := make(map[string]interface{})
117
+	ret["code"] = 400
118
+	if channel == "" {
119
+		log.Println("参数错误 channel")
120
+		ret["msg"] = "缺少参数 channel"
121
+		pack, _ := json.Marshal(ret)
122
+		// 发送成功
123
+		w.Write(pack)
124
+		return
125
+	}
126
+	if si == "" {
127
+		log.Println("参数错误 si")
128
+		ret["msg"] = "缺少参数 uid"
129
+		pack, _ := json.Marshal(ret)
130
+		// 发送成功
131
+		w.Write(pack)
132
+		return
133
+	}
134
+	if bt != 0 && bt != 1 {
135
+		log.Println("参数错误 bt")
136
+		ret["msg"] = "参数值错误 bt"
137
+		pack, _ := json.Marshal(ret)
138
+		// 发送成功
139
+		w.Write(pack)
140
+		return
141
+	}
142
+	if ct != 0 && ct != 2 {
143
+		log.Println("参数错误 ct")
144
+		ret["msg"] = "参数值错误 ct"
145
+		pack, _ := json.Marshal(ret)
146
+		// 发送成功
147
+		w.Write(pack)
148
+		return
149
+	}
150
+	if ct == 0 && pi == "" {
151
+		log.Println("参数错误 pi")
152
+		ret["msg"] = "缺少参数 pi"
153
+		pack, _ := json.Marshal(ret)
154
+		// 发送成功
155
+		w.Write(pack)
156
+		return
157
+	}
158
+	if ct == 2 && di == "" {
159
+		log.Println("参数错误 di si:", si)
160
+		ret["msg"] = "缺少参数 di"
161
+		pack, _ := json.Marshal(ret)
162
+		// 发送成功
163
+		w.Write(pack)
164
+		return
165
+	}
166
+
167
+	chn := utils.StringToInt(channel)
168
+	v, ok := mapChannelToConf.Load(chn)
169
+	if !ok {
170
+		ret["msg"] = "服务器缺少渠道配置"
171
+		pack, _ := json.Marshal(ret)
172
+		// 发送成功
173
+		w.Write(pack)
174
+		return
175
+	}
176
+
177
+	v, ok = mapCollections.Load(v.(*ConfApp).aId)
178
+	if !ok {
179
+		// log.Println(fmt.Sprintf("缺少渠道配置 %d", chn))
180
+		ret["msg"] = "服务器缺少渠道配置"
181
+		pack, _ := json.Marshal(ret)
182
+		// 发送成功
183
+		w.Write(pack)
184
+		return
185
+	}
186
+
187
+	go func() {
188
+		if ct == 2 {
189
+			h := md5.Sum([]byte(di))
190
+			di = hex.EncodeToString(h[:])
191
+		}
192
+
193
+		v.(*nppaCollections).collection <- &Collection{
194
+			Si: si,
195
+			Bt: bt,
196
+			Ot: ot,
197
+			Ct: ct,
198
+			Di: di,
199
+			Pi: pi,
200
+		}
201
+	}()
202
+
203
+	ret["code"] = 200
204
+	ret["msg"] = "成功"
205
+	pack, _ := json.Marshal(ret)
206
+	// 发送成功
207
+	w.Write(pack)
208
+}
209
+
210
+// 实名认证 - 配置更新
211
+func HttpUpdateConfig(w http.ResponseWriter, r *http.Request) {
212
+	ConfUpdate()
213
+	ReportCollections()
214
+}
215
+
216
+// 实名认证 - 测试校验
217
+func HttpTestCheckPlayerID(w http.ResponseWriter, r *http.Request) {
218
+	req := r.URL.Query()
219
+	testCode := req.Get("testCode")
220
+	uid := req.Get("uid")
221
+	name := req.Get("name")
222
+	idNum := req.Get("idNum")
223
+
224
+	ret := TestCheckPlayerId(testCode, uid, name, idNum)
225
+	pack, _ := json.Marshal(ret)
226
+	// 发送成功
227
+	w.Write(pack)
228
+}
229
+
230
+// 实名认证 - 测试查询结果
231
+func HttpTestQueryPlayerID(w http.ResponseWriter, r *http.Request) {
232
+	req := r.URL.Query()
233
+	testCode := req.Get("testCode")
234
+	uid := req.Get("uid")
235
+
236
+	ret := TestQueryPlayerId(testCode, uid)
237
+
238
+	pack, _ := json.Marshal(ret)
239
+	// 发送成功
240
+	w.Write(pack)
241
+}
242
+
243
+// 实名认证 - 测试数据上报
244
+func HttpTestLoginout(w http.ResponseWriter, r *http.Request) {
245
+	req := r.URL.Query()
246
+	testCode := req.Get("testCode")
247
+	si := req.Get("si")
248
+	bt := utils.StringToInt(req.Get("bt"))
249
+	ct := utils.StringToInt(req.Get("ct"))
250
+	di := req.Get("di")
251
+	pi := req.Get("pi")
252
+
253
+	ret := TestLoginout(testCode, si, bt, ct, di, pi)
254
+
255
+	pack, _ := json.Marshal(ret)
256
+	// 发送成功
257
+	w.Write(pack)
258
+}

+ 90 - 0
nppa/interface_test.go

@@ -0,0 +1,90 @@
1
+/*
2
+ * @Author: zkj
3
+ * @Date: 2021-04-25 13:38:31
4
+ * @LastEditTime: 2021-04-25 15:50:07
5
+ * @LastEditors: Please set LastEditors
6
+ * @Description: 实名认证测试
7
+ * @FilePath: /order-server/nppa/interface_test.go
8
+ */
9
+package nppa
10
+
11
+import (
12
+	"crypto/aes"
13
+	"crypto/cipher"
14
+	"crypto/rand"
15
+	"crypto/sha256"
16
+	"encoding/base64"
17
+	"encoding/hex"
18
+	"encoding/json"
19
+	"io"
20
+	"sort"
21
+	"testing"
22
+
23
+	"box-3rdServer/utils"
24
+)
25
+
26
+func TestMakeRequestBody(t *testing.T) {
27
+	mapBody := make(map[string]string)
28
+	mapBody["ai"] = "test-accountId"
29
+	mapBody["name"] = "用户姓名"
30
+	mapBody["idNum"] = "371321199012310912"
31
+
32
+	pack, _ := json.Marshal(mapBody)
33
+
34
+	secretKey := "2836e95fcd10e04b0069bb1ee659955b"
35
+	key, _ := hex.DecodeString(secretKey)
36
+	block, err := aes.NewCipher(key)
37
+	if err != nil {
38
+		t.Fatal(err)
39
+	}
40
+
41
+	aesGcm, err := cipher.NewGCM(block)
42
+	if err != nil {
43
+		t.Fatal(err)
44
+	}
45
+
46
+	nonce := make([]byte, aesGcm.NonceSize())
47
+	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
48
+		t.Fatal(err)
49
+	}
50
+
51
+	cipherText := aesGcm.Seal(nonce, nonce, pack, nil)
52
+
53
+	// encode as base64 string
54
+	encoded := base64.StdEncoding.EncodeToString(cipherText)
55
+
56
+	ret := make(map[string]string)
57
+	ret["data"] = encoded
58
+	pack, _ = json.Marshal(ret)
59
+
60
+	t.Log(string(pack))
61
+}
62
+
63
+func TestMakeRequestSign(t *testing.T) {
64
+	secretKey := "2836e95fcd10e04b0069bb1ee659955b"
65
+	body := `{"data":"CqT/33f3jyoiYqT8MtxEFk3x2rlfhmgzhxpHqWosSj4d3hq2EbrtVyx2aLj565ZQNTcPrcDipnvpq/D/vQDaLKW70O83Q42zvR0//OfnYLcIjTPMnqa+SOhsjQrSdu66ySSORCAo"}`
66
+
67
+	var kvs utils.Kvs
68
+	kvs = append(kvs, &utils.Kv{Key: "appId", Value: "test-appId"})
69
+	kvs = append(kvs, &utils.Kv{Key: "bizId", Value: "test-bizId"})
70
+	kvs = append(kvs, &utils.Kv{Key: "timestamps", Value: "1584949895758"})
71
+	kvs = append(kvs, &utils.Kv{Key: "id", Value: "test-id"})
72
+	kvs = append(kvs, &utils.Kv{Key: "name", Value: "test-name"})
73
+	sort.Sort(kvs)
74
+
75
+	key := ""
76
+	for i := 0; i < kvs.Len(); i++ {
77
+		key += kvs[i].Key + kvs[i].Value
78
+	}
79
+
80
+	strEncode := secretKey + key + body
81
+
82
+	t.Log(strEncode, strEncode == `2836e95fcd10e04b0069bb1ee659955bappIdtest-appIdbizIdtest-bizIdidtest-idnametest-nametimestamps1584949895758{"data":"CqT/33f3jyoiYqT8MtxEFk3x2rlfhmgzhxpHqWosSj4d3hq2EbrtVyx2aLj565ZQNTcPrcDipnvpq/D/vQDaLKW70O83Q42zvR0//OfnYLcIjTPMnqa+SOhsjQrSdu66ySSORCAo"}`)
83
+
84
+	h2 := sha256.New()
85
+	h2.Write([]byte(strEncode))
86
+	hashed := h2.Sum(nil)
87
+
88
+	sign := hex.EncodeToString(hashed)
89
+	t.Log(string(sign), string(sign) == "386c03b776a28c06b8032a958fbd89337424ef45c62d0422706cca633d8ad5fd")
90
+}

+ 165 - 0
nppa/realname.go

@@ -0,0 +1,165 @@
1
+/*
2
+ * @Descripttion:实名认证
3
+ * @version:
4
+ * @Author: Neo,Huang
5
+ * @Date: 2021-04-17 11:04:16
6
+ * @LastEditors: Neo,Huang
7
+ * @LastEditTime: 2021-05-10 15:52:40
8
+ */
9
+package nppa
10
+
11
+import (
12
+	"fmt"
13
+	"log"
14
+
15
+	"box-3rdServer/utils"
16
+
17
+	"github.com/bitly/go-simplejson"
18
+)
19
+
20
+type NppaInfo struct {
21
+	Ai     string `json:"ai,omitempty"`
22
+	Name   string `json:"name,omitempty"`
23
+	IdNum  string `json:"idNum,omitempty"`
24
+	Status int    `json:"status,omitempty"` // -1 未认证 0 认证成功 1 认证中 2 认证失败
25
+	Pi     string `json:"pi,omitempty"`
26
+}
27
+
28
+// 公安部实名认证 - 校验
29
+func NppaCheckPlayerId(chn int, ai string, name string, idNum string) map[string]interface{} {
30
+	ret := make(map[string]interface{})
31
+	ret["code"] = 400
32
+	// 参数错误
33
+	if name == "" || idNum == "" {
34
+
35
+		log.Println("NppaCheckPlayerId 参数错误")
36
+		// 未响应
37
+		ret["msg"] = "参数错误"
38
+		return ret
39
+	}
40
+
41
+	mapHead := ConfGetInfoByChannel(chn)
42
+	if mapHead == nil {
43
+		ret["code"] = 200
44
+		ret["status"] = 0
45
+		// 未响应
46
+		ret["msg"] = "配置错误"
47
+		return ret
48
+	}
49
+
50
+	mapBody := make(map[string]interface{})
51
+	mapBody["ai"] = ai
52
+	mapBody["name"] = name
53
+	mapBody["idNum"] = idNum
54
+
55
+	body := MakeRequestBody(mapBody, mapHead["secretKey"])
56
+	sign := MakeRequestSign(mapHead, nil, body)
57
+	mapHead["sign"] = sign
58
+
59
+	buff, _ := Send2Nppa("POST", utils.GetKeyConf("nppa", "host_check"), mapHead, nil, body)
60
+	j, err := simplejson.NewJson(buff)
61
+	if err != nil {
62
+		log.Println("NppaCheckPlayerId err", err)
63
+		// 未响应
64
+		ret["msg"] = "未响应"
65
+		return ret
66
+	}
67
+	code, _ := j.Get("errcode").Int()
68
+	if code == 0 {
69
+		ret["code"] = 200
70
+		ret["status"], _ = j.Get("data").Get("result").Get("status").Int()
71
+		if ret["status"] == 0 {
72
+			ret["pi"], _ = j.Get("data").Get("result").Get("pi").String()
73
+		}
74
+	} else {
75
+		log.Println(fmt.Sprintf("NppaCheckPlayerId chn[%d] ai[%s] name[%s] idNum[%s] ret[%v]", chn, ai, name, idNum, j))
76
+		if code == 2001 || code == 2002 || code == 2003 || code == 2004 {
77
+			ret["code"] = 200
78
+			ret["status"] = 2 // 这几种情况默认认证失败
79
+		}
80
+	}
81
+	ret["msg"], _ = j.Get("errmsg").String()
82
+	return ret
83
+}
84
+
85
+// 公安部实名认证 - 查询结果
86
+func NppaQueryPlayerId(uid string, chn int) map[string]interface{} {
87
+	ret := make(map[string]interface{})
88
+	ret["code"] = 400
89
+
90
+	mapHead := ConfGetInfoByChannel(chn)
91
+	if mapHead == nil {
92
+		ret["code"] = 200
93
+		ret["status"] = 0
94
+		// 未响应
95
+		ret["msg"] = "配置错误"
96
+		return ret
97
+	}
98
+
99
+	mapParam := make(map[string]string)
100
+	mapParam["ai"] = uid
101
+
102
+	sign := MakeRequestSign(mapHead, mapParam, "")
103
+	mapHead["sign"] = sign
104
+
105
+	buff, _ := Send2Nppa("GET", utils.GetKeyConf("nppa", "host_query"), mapHead, mapParam, "")
106
+	j, err := simplejson.NewJson(buff)
107
+	if err != nil {
108
+		log.Println("NppaQueryPlayerId err", err)
109
+		// 未响应
110
+		ret["msg"] = "未响应"
111
+		return ret
112
+	}
113
+	code, _ := j.Get("errcode").Int()
114
+	if code == 0 {
115
+		ret["code"] = 200
116
+		ret["status"], _ = j.Get("data").Get("result").Get("status").Int()
117
+		if ret["status"] == 0 {
118
+			ret["pi"], _ = j.Get("data").Get("result").Get("pi").String()
119
+		}
120
+	} else {
121
+		log.Println(fmt.Sprintf("NppaQueryPlayerId chn[%d] uid[%s] ret[%v]", chn, uid, j))
122
+		if code == 2001 || code == 2002 || code == 2003 || code == 2004 {
123
+			ret["code"] = 200
124
+			ret["status"] = 2 // 这几种情况默认认证失败
125
+		}
126
+	}
127
+	ret["msg"], _ = j.Get("errmsg").String()
128
+	return ret
129
+}
130
+
131
+// 实名认证 - 校验
132
+func CheckPlayerId(uid int, chn int, name string, idNum string) map[string]interface{} {
133
+	ret := make(map[string]interface{})
134
+	ret["code"] = 400
135
+	if uid < 1000000 {
136
+		log.Println("参数错误 uid")
137
+		ret["msg"] = "参数错误 uid"
138
+		return ret
139
+	}
140
+	if name == "" {
141
+		log.Println("参数错误 name uid:", uid)
142
+		ret["msg"] = "缺少参数 name"
143
+		return ret
144
+	}
145
+	if idNum == "" {
146
+		log.Println("参数错误 idNum")
147
+		ret["msg"] = "缺少参数 idNum"
148
+		return ret
149
+	}
150
+
151
+	return NppaCheckPlayerId(chn, fmt.Sprintf("%032d", uid), name, idNum)
152
+}
153
+
154
+// 实名认证 - 查询
155
+func QueryPlayerId(uid int, chn int) map[string]interface{} {
156
+	ret := make(map[string]interface{})
157
+	ret["code"] = 400
158
+	if uid < 1000000 {
159
+		log.Println("参数错误 uid")
160
+		ret["msg"] = "参数错误 uid"
161
+		return ret
162
+	}
163
+
164
+	return NppaQueryPlayerId(fmt.Sprintf("%032d", uid), chn)
165
+}

+ 254 - 0
nppa/recheck.go

@@ -0,0 +1,254 @@
1
+/*
2
+ * @Descripttion:实名认证
3
+ * @version:
4
+ * @Author: Neo,Huang
5
+ * @Date: 2021-04-17 11:04:16
6
+ * @LastEditors: Neo,Huang
7
+ * @LastEditTime: 2022-04-12 20:27:24
8
+ */
9
+package nppa
10
+
11
+import (
12
+	"bufio"
13
+	"encoding/json"
14
+	"fmt"
15
+	"io"
16
+	"log"
17
+	"os"
18
+	"strconv"
19
+	"strings"
20
+	"time"
21
+
22
+	"box-3rdServer/utils"
23
+
24
+	"github.com/astaxie/beego"
25
+	"github.com/bitly/go-simplejson"
26
+	"github.com/garyburd/redigo/redis"
27
+)
28
+
29
+func getNextTime(now time.Time, startTime string) time.Time {
30
+	arr := strings.Split(startTime, ":")
31
+	hour, _ := strconv.Atoi(arr[0])
32
+	min, _ := strconv.Atoi(arr[1])
33
+	next := time.Date(now.Year(), now.Month(), now.Day(), hour, min, 0, 0, now.Location())
34
+	if now.Before(next) {
35
+		return next
36
+	}
37
+
38
+	next = now.Add(time.Hour * 24)
39
+	next = time.Date(next.Year(), next.Month(), next.Day(), hour, min, 0, 0, next.Location())
40
+	return next
41
+}
42
+
43
+// 备份程序初始化
44
+func InitRecheckProc() {
45
+	title := "存量用户实名认证数据检验"
46
+	timeBackup := utils.GetKeyConf("nppa", "recheck_time")
47
+	if timeBackup == "" {
48
+		// 不开启存量用户同步
49
+		return
50
+	}
51
+	go func() {
52
+		for {
53
+			now := time.Now()
54
+			//返回一个指定时间的下次执行的时间戳
55
+			next := getNextTime(now, timeBackup)
56
+			t := time.NewTimer(next.Sub(now))
57
+			log.Printf("下一次【麻将】 [%s] 开始时间为[%s]", title, next.String())
58
+			<-t.C
59
+			log.Printf("%s--> 神手麻将", title)
60
+			RecheckTimeout()
61
+		}
62
+	}()
63
+}
64
+
65
+// 存量用户 - 重新校验玩家列表key
66
+func RecheckDataKey(isAddDay bool) string {
67
+	now := time.Now()
68
+	if isAddDay {
69
+		now = now.Add(time.Hour * 24)
70
+	}
71
+	keyRecheck := fmt.Sprintf("idRecheck:%d%02d%02d", now.Year(), now.Month(), now.Day())
72
+
73
+	return keyRecheck
74
+}
75
+
76
+// 通知游戏服 - 存量用户验证结果
77
+func UpdatePlayerIdentifyInfo(uid int, m map[string]interface{}) {
78
+	idInfo := utils.GetPlayerInfoFromRedis(uid, utils.GetKeyConf("nppa", "key_id_info"))
79
+	if idInfo == "" {
80
+		idInfo = "{}"
81
+	}
82
+
83
+	j, err := simplejson.NewJson([]byte(idInfo))
84
+	if err != nil {
85
+		log.Println("UpdatePlayerIdentifyInfo err:", err)
86
+		return
87
+	}
88
+	if m["status"] == 0 || m["status"] == 1 {
89
+		j.Set("nppaStatus", m["status"])
90
+		j.Set("pi", m["pi"])
91
+		j.Set("jmIDName", m["name"])
92
+		j.Set("jmIDCard", m["idNum"])
93
+		j.Set("lastCheckTime", time.Now().Unix())
94
+		j.Set("award", true)
95
+	} else {
96
+		j.Del("nppaStatus")
97
+		j.Del("birthType")
98
+		j.Del("jmBirthDate")
99
+		j.Del("jmName")
100
+		j.Del("jmIDCard")
101
+	}
102
+	buff, _ := json.Marshal(j)
103
+	idInfo = string(buff)
104
+
105
+	utils.SetPlayerInfoFromRedis(uid, utils.GetKeyConf("nppa", "key_id_info"), idInfo)
106
+}
107
+
108
+// 存量玩家重新实名认证
109
+func RecheckPlayerId(uid int) {
110
+	// 玩家信息是否已备份
111
+	if !utils.IsPlayerExistInRedis(uid) {
112
+		return
113
+	}
114
+	// 根据项目获取玩家已实名认证数据
115
+	// name:玩家实名认证姓名
116
+	// idNum:玩家实名认证身份证号码
117
+	idInfo := GetJiamiIdInfo(uid)
118
+	if idInfo["name"] == "" || idInfo["idNum"] == "" || idInfo["chn"] == "" {
119
+		return
120
+	}
121
+
122
+	ret := NppaCheckPlayerId(utils.StringToInt(idInfo["chn"]), fmt.Sprintf("%032d", uid), idInfo["name"], idInfo["idNum"])
123
+	// log.Printf("RecheckPlayerId uid[%d] ret[%v]", uid, ret)
124
+
125
+	keyRecheck := RecheckDataKey(true)
126
+	// 认证中 - 放入重新校验列表
127
+	if ret["code"] == 200 {
128
+		if ret["status"] == 1 {
129
+			utils.Sadd(keyRecheck, utils.IntToString(uid))
130
+
131
+		} else {
132
+			ret["name"] = idInfo["name"]
133
+			ret["idNum"] = idInfo["idNum"]
134
+			UpdatePlayerIdentifyInfo(uid, ret)
135
+		}
136
+	}
137
+}
138
+
139
+// 存量玩家重新实名认证
140
+func RecheckQueryPlayerId(uid int) {
141
+	// 根据项目获取玩家已实名认证数据
142
+	// name:玩家实名认证姓名
143
+	// idNum:玩家实名认证身份证号码
144
+	idInfo := GetJiamiIdInfo(uid)
145
+	if idInfo["name"] == "" || idInfo["idNum"] == "" || idInfo["chn"] == "" {
146
+		// 旧数据已删除
147
+		return
148
+	}
149
+
150
+	ret := NppaQueryPlayerId(fmt.Sprintf("%032d", uid), utils.StringToInt(idInfo["chn"]))
151
+
152
+	keyRecheck := RecheckDataKey(true)
153
+	// 失败 - 放入重新校验列表
154
+	if ret["code"] == 200 {
155
+		if ret["status"] == 1 {
156
+			utils.Sadd(keyRecheck, utils.IntToString(uid))
157
+
158
+		} else {
159
+			ret["name"] = idInfo["name"]
160
+			ret["idNum"] = idInfo["idNum"]
161
+			UpdatePlayerIdentifyInfo(uid, ret)
162
+		}
163
+	}
164
+}
165
+
166
+// 获取玩家uid列表 - 文件形式
167
+func RecheckPlayersFromFile() {
168
+	// 已经跑过文件
169
+	if utils.GetAccountKeyInfo("idRecheck") != "" {
170
+		return
171
+	}
172
+	project := utils.GetConfigPath()
173
+	sFile := fmt.Sprintf("%srecheck_uids.txt", project)
174
+	if beego.AppConfig.String("runmode") == "test" {
175
+		sFile = fmt.Sprintf("%srecheck_uids_test.txt", project)
176
+	}
177
+	// 重新创建
178
+	f, err2 := os.OpenFile(sFile, os.O_CREATE|os.O_RDONLY, 0666)
179
+	if err2 != nil {
180
+		log.Println("打开配置文件失败 ", sFile)
181
+		return
182
+	}
183
+	defer f.Close()
184
+
185
+	title := "重新验证玩家实名认证数据"
186
+
187
+	log.Printf("开始 - %s - 文件", title)
188
+	buff := bufio.NewReader(f)
189
+	pos := 0
190
+	for {
191
+		// line, err := buff.ReadString('\n')
192
+		line, _, err := buff.ReadLine()
193
+
194
+		if err != nil || io.EOF == err {
195
+			break
196
+		}
197
+		// line = strings.TrimSpace(line)
198
+
199
+		uid := utils.StringToInt(strings.TrimSpace(string(line)))
200
+		log.Printf("%s uid[%d]", title, uid)
201
+		pos += 1
202
+		if uid >= 1000000 {
203
+			RecheckPlayerId(uid)
204
+			time.Sleep(100 * time.Millisecond)
205
+		}
206
+	}
207
+
208
+	utils.SetAccountKeyInfo("idRecheck", time.Now().Format("2006-01-02"))
209
+
210
+	log.Printf("结束 - %s - 文件", title)
211
+}
212
+
213
+// key数据是否存在
214
+func IsKeyExistInRedis(key string) bool {
215
+	pool := utils.GetAccountRedisPool()
216
+	if pool == nil {
217
+		fmt.Println("get redis pool fail")
218
+		return false
219
+	}
220
+	rd := pool.Get()
221
+	defer rd.Close()
222
+
223
+	is_key_exit, _ := redis.Bool(rd.Do("EXISTS", key))
224
+
225
+	return is_key_exit
226
+}
227
+
228
+// 定时器 - 结束
229
+func RecheckTimeout() {
230
+	keyRecheck := RecheckDataKey(false)
231
+	if IsKeyExistInRedis(keyRecheck) {
232
+		pool := utils.GetAccountRedisPool()
233
+		if pool == nil {
234
+			fmt.Println("get redis pool fail")
235
+			return
236
+		}
237
+		rd := pool.Get()
238
+		defer rd.Close()
239
+
240
+		title := "查询结果玩家实名认证数据"
241
+		log.Printf("开始 - %s - 查询结果", title)
242
+		result, _ := redis.Values(rd.Do("smembers", keyRecheck))
243
+		for _, v2 := range result {
244
+			uid := utils.StringToInt(string(v2.([]byte)))
245
+			log.Printf("%s uid[%d]", title, uid)
246
+			RecheckQueryPlayerId(uid)
247
+
248
+			time.Sleep(100 * time.Millisecond)
249
+		}
250
+		log.Printf("结束 - %s - 查询结果", title)
251
+	} else {
252
+		RecheckPlayersFromFile()
253
+	}
254
+}

+ 155 - 0
nppa/report.go

@@ -0,0 +1,155 @@
1
+/*
2
+ * @Descripttion:实名认证
3
+ * @version:
4
+ * @Author: Neo,Huang
5
+ * @Date: 2021-04-17 11:04:16
6
+ * @LastEditors: Please set LastEditors
7
+ * @LastEditTime: 2021-05-10 16:12:02
8
+ */
9
+package nppa
10
+
11
+import (
12
+	"encoding/json"
13
+	"fmt"
14
+	"log"
15
+	"math/rand"
16
+	"sync"
17
+	"time"
18
+
19
+	"box-3rdServer/utils"
20
+
21
+	"github.com/bitly/go-simplejson"
22
+)
23
+
24
+type Collection struct {
25
+	No int    `json:"no,omitempty"` //条目编号
26
+	Si string `json:"si,omitempty"` //游戏内部会话标识
27
+	Bt int    `json:"bt"`           //用户行为类型
28
+	Ot int    `json:"ot,omitempty"` //行为发生时间
29
+	Ct int    `json:"ct"`           //上报类型
30
+	Di string `json:"di,omitempty"` //设备标识
31
+	Pi string `json:"pi,omitempty"` //用户唯一标识
32
+}
33
+
34
+type nppaCollections struct {
35
+	aid        int
36
+	collection chan *Collection
37
+	timer      *time.Timer
38
+	close      chan int
39
+}
40
+
41
+var mapCollections sync.Map
42
+
43
+var aidKey = "nppa:aid:%d"
44
+
45
+var interval = time.Duration(120) //秒
46
+
47
+func sendCollections(aid int, key string) {
48
+	infos := utils.Zrange(key, 0, 127)
49
+	collections := []*Collection{}
50
+	for k, v := range infos {
51
+		collection := Collection{No: k + 1}
52
+		json.Unmarshal([]byte(v), &collection)
53
+		collections = append(collections, &collection)
54
+	}
55
+	NppaReportCollections(aid, collections)
56
+	utils.Zremrangebyrank(key, 0, len(infos)-1)
57
+}
58
+
59
+func getRandomInterval() time.Duration {
60
+	rand.Seed(time.Now().UnixNano())
61
+	return time.Duration(rand.Intn(21) - 10)
62
+}
63
+
64
+func ReportCollections() {
65
+	mapCollections.Range(func(k, v interface{}) bool {
66
+		_, ok := mapAidToConf.Load(k)
67
+		if !ok {
68
+			nppaCollections := v.(*nppaCollections)
69
+			nppaCollections.close <- 1
70
+			mapCollections.Delete(k)
71
+		}
72
+		return true
73
+	})
74
+
75
+	mapAidToConf.Range(func(k, v interface{}) bool {
76
+		_, ok := mapCollections.Load(k)
77
+		if !ok {
78
+			nppaCollections := nppaCollections{
79
+				aid:        k.(int),
80
+				collection: make(chan *Collection),
81
+				timer:      time.NewTimer(interval * time.Second),
82
+				close:      make(chan int),
83
+			}
84
+
85
+			key := fmt.Sprintf(aidKey, nppaCollections.aid)
86
+
87
+			go func() {
88
+				for {
89
+					select {
90
+					case collection := <-nppaCollections.collection:
91
+						info, _ := json.Marshal(collection)
92
+						utils.Zadd(key, collection.Ot, string(info))
93
+						if utils.Zcard(key) >= 128 {
94
+							sendCollections(nppaCollections.aid, key)
95
+							if len(nppaCollections.timer.C) > 0 {
96
+								<-nppaCollections.timer.C
97
+							}
98
+							nppaCollections.timer.Reset((interval + getRandomInterval()) * time.Second)
99
+						}
100
+					case <-nppaCollections.timer.C:
101
+						if utils.Zcard(key) > 0 {
102
+							sendCollections(nppaCollections.aid, key)
103
+						}
104
+						nppaCollections.timer.Reset((interval + getRandomInterval()) * time.Second)
105
+					case <-nppaCollections.close:
106
+						return
107
+					}
108
+				}
109
+			}()
110
+
111
+			mapCollections.Store(k, &nppaCollections)
112
+		}
113
+		return true
114
+	})
115
+}
116
+
117
+// 玩家行为数据上报
118
+func NppaReportCollections(aid int, collections []*Collection) {
119
+	mapHead := ConfGetInfoByAid(aid)
120
+	if mapHead == nil {
121
+		return
122
+	}
123
+
124
+	mapBody := make(map[string]interface{})
125
+	mapBody["collections"] = collections
126
+
127
+	body := MakeRequestBody(mapBody, mapHead["secretKey"])
128
+	sign := MakeRequestSign(mapHead, nil, body)
129
+	mapHead["sign"] = sign
130
+
131
+	buff, errReq := Send2Nppa("POST", utils.GetKeyConf("nppa", "host_loginout"), mapHead, nil, body)
132
+	j, err := simplejson.NewJson(buff)
133
+	if err != nil {
134
+		log.Printf("NppaReportCollections err[%v] errReq[%v]", err, errReq)
135
+		return
136
+	}
137
+	code, _ := j.Get("errcode").Int()
138
+	msg, _ := j.Get("errmsg").String()
139
+	if code != 0 {
140
+		log.Println(fmt.Sprintf("NppaReportCollections err code[%d] msg[%s]", code, msg))
141
+		for _, v := range collections {
142
+			log.Println(fmt.Sprintf("collection %v", v))
143
+		}
144
+		return
145
+	}
146
+	for _, v := range j.Get("data").Get("results").MustArray() {
147
+		result, _ := v.(map[string]interface{})
148
+		no := utils.JsonNumberToInt(result["no"])
149
+		errcode := utils.JsonNumberToInt(result["errcode"])
150
+		errmsg := result["errmsg"].(string)
151
+		if errcode != 0 {
152
+			log.Println(fmt.Sprintf("NppaReportCollections err collection[%v] ot[%d] code[%d] msg[%s]", collections[no-1], collections[no-1].Ot, errcode, errmsg))
153
+		}
154
+	}
155
+}

+ 162 - 0
nppa/test.go

@@ -0,0 +1,162 @@
1
+/*
2
+ * @Descripttion:实名认证
3
+ * @version:
4
+ * @Author: Neo,Huang
5
+ * @Date: 2021-04-17 11:04:16
6
+ * @LastEditors: Neo,Huang
7
+ * @LastEditTime: 2021-05-06 14:46:17
8
+ */
9
+package nppa
10
+
11
+import (
12
+	"fmt"
13
+	"log"
14
+	"time"
15
+
16
+	"github.com/bitly/go-simplejson"
17
+)
18
+
19
+// 实名认证 - 测试校验
20
+func TestCheckPlayerId(testCode string, uid string, name string, idNum string) map[string]interface{} {
21
+	ret := make(map[string]interface{})
22
+	ret["code"] = 400
23
+
24
+	url := fmt.Sprintf("https://wlc.nppa.gov.cn/test/authentication/check/%s", testCode)
25
+	log.Println("TestCheckPlayerId url:", url)
26
+
27
+	chn := -1
28
+	mapHead := ConfGetInfoByChannel(chn)
29
+	if mapHead == nil {
30
+		// 未响应
31
+		ret["msg"] = "配置错误"
32
+		return ret
33
+	}
34
+
35
+	mapBody := make(map[string]interface{})
36
+	mapBody["ai"] = uid
37
+	mapBody["name"] = name
38
+	mapBody["idNum"] = idNum
39
+
40
+	body := MakeRequestBody(mapBody, mapHead["secretKey"])
41
+	sign := MakeRequestSign(mapHead, nil, body)
42
+	log.Println(fmt.Sprintf("TestCheckPlayerId body[%s] sign[%s]", body, sign))
43
+	mapHead["sign"] = sign
44
+
45
+	buff, _ := Send2Nppa("POST", url, mapHead, nil, body)
46
+	j, err := simplejson.NewJson(buff)
47
+	if err != nil {
48
+		log.Println("TestCheckPlayerId err", err)
49
+		// 未响应
50
+		ret["msg"] = "未响应"
51
+		return ret
52
+	}
53
+	code, _ := j.Get("errcode").Int()
54
+	if code == 0 {
55
+		ret["code"] = 200
56
+	} else {
57
+		log.Println("TestCheckPlayerId ret:", j)
58
+	}
59
+	ret["msg"], _ = j.Get("errmsg").String()
60
+
61
+	return ret
62
+}
63
+
64
+// 实名认证 - 测试查询结果
65
+func TestQueryPlayerId(testCode string, uid string) map[string]interface{} {
66
+	ret := make(map[string]interface{})
67
+	ret["code"] = 400
68
+
69
+	url := fmt.Sprintf("https://wlc.nppa.gov.cn/test/authentication/query/%s", testCode)
70
+	log.Println("TestQueryPlayerId url:", url)
71
+
72
+	chn := -1
73
+	mapHead := ConfGetInfoByChannel(chn)
74
+	if mapHead == nil {
75
+		// 未响应
76
+		ret["msg"] = "配置错误"
77
+		return ret
78
+	}
79
+
80
+	mapParam := make(map[string]string)
81
+	mapParam["ai"] = uid
82
+
83
+	sign := MakeRequestSign(mapHead, mapParam, "")
84
+	log.Println(fmt.Sprintf("TestQueryPlayerId uid[%s] sign[%s]", uid, sign))
85
+	mapHead["sign"] = sign
86
+
87
+	buff, _ := Send2Nppa("GET", url, mapHead, mapParam, "")
88
+	j, err := simplejson.NewJson(buff)
89
+	if err != nil {
90
+		log.Println("TestQueryPlayerId err", err)
91
+		// 未响应
92
+		ret["msg"] = "未响应"
93
+
94
+		return ret
95
+	}
96
+	code, _ := j.Get("errcode").Int()
97
+	if code == 0 {
98
+		ret["code"] = 200
99
+	} else {
100
+		log.Println("TestQueryPlayerId ret:", j)
101
+	}
102
+	ret["msg"], _ = j.Get("errmsg").String()
103
+
104
+	return ret
105
+}
106
+
107
+// 实名认证 - 测试数据上报
108
+func TestLoginout(testCode string, si string, bt int, ct int, di string, pi string) map[string]interface{} {
109
+	ret := make(map[string]interface{})
110
+	ret["code"] = 400
111
+
112
+	url := fmt.Sprintf("https://wlc.nppa.gov.cn/test/collection/loginout/%s", testCode)
113
+	log.Println("TestLoginout url:", url)
114
+
115
+	chn := -1
116
+	mapHead := ConfGetInfoByChannel(chn)
117
+	if mapHead == nil {
118
+		// 未响应
119
+		ret["msg"] = "配置错误"
120
+		return ret
121
+	}
122
+
123
+	mapBody := make(map[string]interface{})
124
+	collections := []map[string]interface{}{}
125
+	collection := make(map[string]interface{})
126
+	collection["no"] = 1
127
+	collection["si"] = si
128
+	collection["bt"] = bt
129
+	collection["ot"] = time.Now().Unix()
130
+	collection["ct"] = ct
131
+	if ct == 0 {
132
+		collection["pi"] = pi
133
+	} else if ct == 2 {
134
+		collection["di"] = di
135
+	}
136
+	collections = append(collections, collection)
137
+	mapBody["collections"] = collections
138
+
139
+	body := MakeRequestBody(mapBody, mapHead["secretKey"])
140
+	sign := MakeRequestSign(mapHead, nil, body)
141
+	log.Println(fmt.Sprintf("TestLoginout body[%s] sign[%s]", body, sign))
142
+	mapHead["sign"] = sign
143
+
144
+	buff, _ := Send2Nppa("POST", url, mapHead, nil, body)
145
+	j, err := simplejson.NewJson(buff)
146
+	if err != nil {
147
+		log.Println("TestLoginout err", err)
148
+		// 未响应
149
+		ret["msg"] = "未响应"
150
+
151
+		return ret
152
+	}
153
+	code, _ := j.Get("errcode").Int()
154
+	if code == 0 {
155
+		ret["code"] = 200
156
+	} else {
157
+		log.Println("TestLoginout ret:", j)
158
+	}
159
+	ret["msg"], _ = j.Get("errmsg").String()
160
+
161
+	return ret
162
+}

+ 317 - 0
nppa/util.go

@@ -0,0 +1,317 @@
1
+/*
2
+ * @Descripttion:实名认证
3
+ * @version:
4
+ * @Author: Neo,Huang
5
+ * @Date: 2021-04-17 11:04:16
6
+ * @LastEditors: Neo,Huang
7
+ * @LastEditTime: 2022-04-12 20:27:43
8
+ */
9
+package nppa
10
+
11
+import (
12
+	"crypto/aes"
13
+	"crypto/cipher"
14
+	"crypto/rand"
15
+	"crypto/sha256"
16
+	"encoding/base64"
17
+	"encoding/hex"
18
+	"encoding/json"
19
+	"fmt"
20
+	"io"
21
+	"io/ioutil"
22
+	"log"
23
+	"net/http"
24
+	"net/url"
25
+	"sort"
26
+	"strconv"
27
+	"strings"
28
+	"sync"
29
+	"time"
30
+
31
+	"box-3rdServer/utils"
32
+
33
+	"github.com/bitly/go-simplejson"
34
+)
35
+
36
+type ConfApp struct {
37
+	aId       int
38
+	appId     string
39
+	appName   string
40
+	bizId     string
41
+	secretKey string
42
+}
43
+
44
+var mapAidToConf sync.Map
45
+var mapChannelToConf sync.Map
46
+
47
+// 初始化
48
+func initConf() {
49
+	path := utils.GetConfigPath()
50
+	j := utils.LoadJsonFile(path + "NppaAppConfig.json")
51
+	tmpMapAidToConf := make(map[int]*ConfApp)
52
+	mapAppNameToConf := make(map[string]*ConfApp)
53
+	for _, v := range j.MustArray() {
54
+		item, _ := v.(map[string]interface{})
55
+		val, ok := item["aId"]
56
+		if !ok {
57
+			continue
58
+		}
59
+		aId := utils.JsonNumberToInt(val)
60
+		conf := &ConfApp{aId: aId}
61
+		val, ok = item["appId"]
62
+		if ok {
63
+			conf.appId = val.(string)
64
+		}
65
+		val, ok = item["appName"]
66
+		if ok {
67
+			conf.appName = val.(string)
68
+		}
69
+		val, ok = item["bizId"]
70
+		if ok {
71
+			conf.bizId = val.(string)
72
+		}
73
+		val, ok = item["secretKey"]
74
+		if ok {
75
+			conf.secretKey = val.(string)
76
+		}
77
+		tmpMapAidToConf[aId] = conf
78
+		mapAppNameToConf[conf.appName] = conf
79
+	}
80
+
81
+	j = utils.LoadJsonFile(path + "NppaChannelConfig.json")
82
+	mapChannelToAid := make(map[int]int)
83
+	mapChannelToAppName := make(map[int]string)
84
+	for _, v := range j.MustArray() {
85
+		item, _ := v.(map[string]interface{})
86
+		val, ok := item["channel"]
87
+		if !ok {
88
+			continue
89
+		}
90
+		channel := utils.JsonNumberToInt(val)
91
+		val, ok = item["aId"]
92
+
93
+		if ok {
94
+			mapChannelToAid[channel] = utils.JsonNumberToInt(val)
95
+		}
96
+		val, ok = item["appName"]
97
+		if ok {
98
+			mapChannelToAppName[channel] = val.(string)
99
+		}
100
+	}
101
+
102
+	mapAidToConf.Range(func(k, v interface{}) bool {
103
+		_, ok := tmpMapAidToConf[k.(int)]
104
+		if !ok {
105
+			mapAidToConf.Delete(k)
106
+		}
107
+		return true
108
+	})
109
+	for k, v := range tmpMapAidToConf {
110
+		mapAidToConf.Store(k, v)
111
+	}
112
+
113
+	mapTmp := make(map[int]*ConfApp)
114
+	for k, v := range mapChannelToAid {
115
+		conf, ok := tmpMapAidToConf[v]
116
+		if ok {
117
+			mapTmp[k] = conf
118
+		}
119
+	}
120
+
121
+	mapChannelToConf.Range(func(k, v interface{}) bool {
122
+		_, ok := mapTmp[k.(int)]
123
+		if !ok {
124
+			mapChannelToConf.Delete(k)
125
+		}
126
+		return true
127
+	})
128
+	for k, v := range mapTmp {
129
+		mapChannelToConf.Store(k, v)
130
+	}
131
+}
132
+
133
+// 配置更新
134
+func ConfUpdate() {
135
+	initConf()
136
+}
137
+
138
+// 渠道配置
139
+func ConfGetInfoByAid(aid int) map[string]string {
140
+	v, ok := mapAidToConf.Load(aid)
141
+	if !ok {
142
+		return nil
143
+	}
144
+	conf := v.(*ConfApp)
145
+
146
+	info := make(map[string]string)
147
+	info["appId"] = conf.appId
148
+	info["bizId"] = conf.bizId
149
+	info["secretKey"] = conf.secretKey
150
+	info["timestamps"] = fmt.Sprintf("%v", time.Now().UnixNano()/1e6)
151
+
152
+	return info
153
+}
154
+
155
+// 渠道配置
156
+func ConfGetInfoByChannel(chn int) map[string]string {
157
+	v, ok := mapChannelToConf.Load(chn)
158
+	if !ok {
159
+		return nil
160
+	}
161
+	conf := v.(*ConfApp)
162
+
163
+	info := make(map[string]string)
164
+	info["appId"] = conf.appId
165
+	info["bizId"] = conf.bizId
166
+	info["secretKey"] = conf.secretKey
167
+	info["timestamps"] = fmt.Sprintf("%v", time.Now().UnixNano()/1e6)
168
+
169
+	return info
170
+}
171
+
172
+// 创建请求消息body
173
+func MakeRequestBody(m map[string]interface{}, secretKey string) string {
174
+	pack, _ := json.Marshal(m)
175
+
176
+	key, _ := hex.DecodeString(secretKey)
177
+	block, err := aes.NewCipher(key)
178
+	if err != nil {
179
+		return ""
180
+	}
181
+
182
+	aesGcm, err := cipher.NewGCM(block)
183
+	if err != nil {
184
+		return ""
185
+	}
186
+	// 向量
187
+	nonce := make([]byte, aesGcm.NonceSize())
188
+	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
189
+		return ""
190
+	}
191
+
192
+	cipherText := aesGcm.Seal(nonce, nonce, pack, nil)
193
+
194
+	// encode as base64 string
195
+	encoded := base64.StdEncoding.EncodeToString(cipherText)
196
+
197
+	ret := make(map[string]string)
198
+	ret["data"] = encoded
199
+	pack, _ = json.Marshal(ret)
200
+
201
+	return string(pack)
202
+}
203
+
204
+// 签名
205
+func MakeRequestSign(heads map[string]string, params map[string]string, body string) string {
206
+	var kvs utils.Kvs
207
+	kvs = append(kvs, &utils.Kv{Key: "appId", Value: heads["appId"]})
208
+	kvs = append(kvs, &utils.Kv{Key: "bizId", Value: heads["bizId"]})
209
+	kvs = append(kvs, &utils.Kv{Key: "timestamps", Value: heads["timestamps"]})
210
+	for k, v := range params {
211
+		kvs = append(kvs, &utils.Kv{Key: k, Value: url.QueryEscape(v)})
212
+	}
213
+	sort.Sort(kvs)
214
+
215
+	key := ""
216
+	for i := 0; i < kvs.Len(); i++ {
217
+		key += kvs[i].Key + kvs[i].Value
218
+	}
219
+
220
+	strEncode := heads["secretKey"] + key + body
221
+
222
+	h2 := sha256.New()
223
+	h2.Write([]byte(strEncode))
224
+	hashed := h2.Sum(nil)
225
+
226
+	sign := hex.EncodeToString(hashed)
227
+	// log.Println(fmt.Sprintf("MakeRequestSign strEncode[%s] sign[%s]", strEncode, sign))
228
+
229
+	return sign
230
+}
231
+
232
+// 请求 网络游戏防沉迷实名认证系统
233
+func Send2Nppa(method string, url string, heads map[string]string, params map[string]string, body string) ([]byte, error) {
234
+	if len(params) > 0 {
235
+		url += "?"
236
+		for k, v := range params {
237
+			url += k + "=" + v + "&"
238
+		}
239
+		url = url[:len(url)-1]
240
+	}
241
+	req, err1 := http.NewRequest(method, url, strings.NewReader(body))
242
+	if err1 != nil {
243
+		return nil, err1
244
+	}
245
+	req.Header.Set("Content-Type", "application/json;charset=utf-8")
246
+	req.Header.Set("appId", heads["appId"])
247
+	req.Header.Set("bizId", heads["bizId"])
248
+	req.Header.Set("timestamps", heads["timestamps"])
249
+	req.Header.Set("sign", heads["sign"])
250
+
251
+	client := &http.Client{}
252
+	resp, err2 := client.Do(req)
253
+	if err2 != nil {
254
+		return nil, err2
255
+	}
256
+	defer resp.Body.Close()
257
+
258
+	return ioutil.ReadAll(resp.Body)
259
+}
260
+
261
+// 测试签名
262
+func TestSign() string {
263
+	mapBody := make(map[string]interface{})
264
+	mapBody["id"] = "test-id"
265
+	mapBody["name"] = "test-name"
266
+	mapInfo := make(map[string]string)
267
+	mapInfo["appId"] = "test-appId"
268
+	mapInfo["bizId"] = "test-bizId"
269
+	mapInfo["secretKey"] = "2836e95fcd10e04b0069bb1ee659955b"
270
+	mapInfo["timestamps"] = "1584949895758"
271
+
272
+	body := MakeRequestBody(mapBody, mapInfo["secretKey"])
273
+	sign := MakeRequestSign(mapInfo, nil, body)
274
+	// log.Println(fmt.Sprintf("TestSign sign[%s]", sign))
275
+
276
+	return sign
277
+}
278
+
279
+// 获取玩家嘉米实名认证信息
280
+func GetJiamiIdInfo(uid int) map[string]string {
281
+	project := utils.GetProject()
282
+
283
+	idInfo := make(map[string]string)
284
+	// 麻将
285
+	if project == "mahjong" {
286
+		idInfo = GetMahjongIdInfo(uid)
287
+	} else if project == "H5ddz" {
288
+		idInfo = GetH5ddzIdInfo(uid)
289
+	}
290
+
291
+	return idInfo
292
+}
293
+func GetMahjongIdInfo(uid int) map[string]string {
294
+	idInfo := make(map[string]string)
295
+	idInfo["name"] = utils.GetPlayerInfoFromRedis(uid, "jmIDName")
296
+	idInfo["idNum"] = utils.GetPlayerInfoFromRedis(uid, "jmIDCard")
297
+	idInfo["chn"] = utils.GetPlayerInfoFromRedis(uid, "channel")
298
+
299
+	return idInfo
300
+}
301
+func GetH5ddzIdInfo(uid int) map[string]string {
302
+	idInfo := make(map[string]string)
303
+	info := utils.GetPlayerInfoFromRedis(uid, "info")
304
+
305
+	j, err := simplejson.NewJson([]byte(info))
306
+	if err != nil {
307
+		log.Println("GetH5ddzIdInfo err:", err)
308
+		return idInfo
309
+	}
310
+
311
+	idInfo["name"], _ = j.Get("antiAddiData").Get("identityName").String()
312
+	idInfo["idNum"], _ = j.Get("antiAddiData").Get("identity").String()
313
+	strChannel, _ := j.Get("channel").Int()
314
+	idInfo["chn"] = strconv.Itoa(strChannel)
315
+
316
+	return idInfo
317
+}

+ 169 - 2
utils/redis.go

@@ -16,12 +16,15 @@ import (
16 16
 	"github.com/garyburd/redigo/redis"
17 17
 	redigo "github.com/gomodule/redigo/redis"
18 18
 )
19
+
19 20
 type Redis struct {
20
-	pool     *redigo.Pool
21
+	pool *redigo.Pool
21 22
 }
23
+
22 24
 // 连接池
23 25
 var mapRedisPool = make(map[string](map[int]*Redis))
24 26
 var mapAccountRedisPool = make(map[string]*Redis)
27
+
25 28
 // 实例数量
26 29
 var mapRedisCount = make(map[string]int)
27 30
 
@@ -32,6 +35,7 @@ func InitRedis() bool {
32 35
 	mapRedisCount[project] = count
33 36
 	return true
34 37
 }
38
+
35 39
 // 获取玩家连接池
36 40
 func GetPlayerRedisPool(uid int) *redigo.Pool {
37 41
 	project := GetProject()
@@ -76,6 +80,7 @@ func GetPlayerRedisPool(uid int) *redigo.Pool {
76 80
 	}
77 81
 	return redisConn.pool
78 82
 }
83
+
79 84
 // 获取account redis连接池
80 85
 func GetAccountRedisPool() *redigo.Pool {
81 86
 	project := GetProject()
@@ -221,4 +226,166 @@ func DelPlayerInfo(uid int) bool {
221 226
 	}
222 227
 
223 228
 	return true
224
-}
229
+}
230
+
231
+// 获取玩家信息key
232
+func KeyPlayerInfo(uid int) string {
233
+	keyPrefix := GetKeyConf("player", "key_player_info_prefix")
234
+	if keyPrefix == "" {
235
+		keyPrefix = "player:uid:"
236
+	}
237
+	return fmt.Sprintf("%s%d", keyPrefix, uid)
238
+}
239
+
240
+// key数据是否存在
241
+func IsPlayerExistInRedis(uid int) bool {
242
+	pool := GetPlayerRedisPool(uid)
243
+	if pool == nil {
244
+		fmt.Println("get redis pool fail")
245
+		return false
246
+	}
247
+	rd := pool.Get()
248
+	defer rd.Close()
249
+
250
+	key := KeyPlayerInfo(uid)
251
+	is_key_exit, _ := redis.Bool(rd.Do("EXISTS", key))
252
+
253
+	return is_key_exit
254
+}
255
+
256
+// Zadd
257
+func Zadd(key string, score int, value string) {
258
+	pool := GetPlayerRedisPool(0)
259
+	if pool == nil {
260
+		fmt.Println("get redis pool fail")
261
+		return
262
+	}
263
+	redisConn := pool.Get()
264
+	if redisConn == nil {
265
+		fmt.Println("get redis conn fail")
266
+		return
267
+	}
268
+	defer redisConn.Close()
269
+
270
+	_, err := redisConn.Do("zadd", key, score, value)
271
+	if err != nil {
272
+		fmt.Println("Zadd err:", err)
273
+	}
274
+}
275
+
276
+// Zcard
277
+func Zcard(key string) int {
278
+	pool := GetPlayerRedisPool(0)
279
+	if pool == nil {
280
+		fmt.Println("get redis pool fail")
281
+		return 0
282
+	}
283
+	redisConn := pool.Get()
284
+	if redisConn == nil {
285
+		fmt.Println("get redis conn fail")
286
+		return 0
287
+	}
288
+	defer redisConn.Close()
289
+
290
+	reply, err := redisConn.Do("zcard", key)
291
+	if err != nil {
292
+		fmt.Println("Zcard err:", err)
293
+		return 0
294
+	}
295
+	count, _ := redis.Int(reply, err)
296
+	return count
297
+}
298
+
299
+// Zrange
300
+func Zrange(key string, start int, end int) []string {
301
+	pool := GetPlayerRedisPool(0)
302
+	if pool == nil {
303
+		fmt.Println("get redis pool fail")
304
+		return nil
305
+	}
306
+	redisConn := pool.Get()
307
+	if redisConn == nil {
308
+		fmt.Println("get redis conn fail")
309
+		return nil
310
+	}
311
+	defer redisConn.Close()
312
+
313
+	reply, err := redisConn.Do("zrange", key, start, end)
314
+	if err != nil {
315
+		fmt.Println("Zrange err:", err)
316
+		return nil
317
+	}
318
+	result, _ := redis.Strings(reply, err)
319
+	return result
320
+}
321
+
322
+// Zremrangebyrank
323
+func Zremrangebyrank(key string, start int, end int) {
324
+	pool := GetPlayerRedisPool(0)
325
+	if pool == nil {
326
+		fmt.Println("get redis pool fail")
327
+		return
328
+	}
329
+	redisConn := pool.Get()
330
+	if redisConn == nil {
331
+		fmt.Println("get redis conn fail")
332
+		return
333
+	}
334
+	defer redisConn.Close()
335
+
336
+	_, err := redisConn.Do("zremrangebyrank", key, start, end)
337
+	if err != nil {
338
+		fmt.Println("Zremrangebyrank err:", err)
339
+	}
340
+}
341
+
342
+// sadd
343
+func Sadd(key string, val string) {
344
+
345
+	pool := GetAccountRedisPool()
346
+	if pool == nil {
347
+		fmt.Println("get redis pool fail")
348
+		return
349
+	}
350
+	rd := pool.Get()
351
+	defer rd.Close()
352
+
353
+	rd.Do("sadd", key, val)
354
+}
355
+
356
+// 获取redis key信息
357
+func GetAccountKeyInfo(key string) string {
358
+	pool := GetAccountRedisPool()
359
+	if pool == nil {
360
+		fmt.Println("get redis pool fail")
361
+		return ""
362
+	}
363
+	rd := pool.Get()
364
+	defer rd.Close()
365
+
366
+	val, err1 := redis.String(rd.Do("GET", key))
367
+	if err1 != nil {
368
+		log.Printf("redis GET %s fail! err:%v", key, err1)
369
+		return ""
370
+	}
371
+	return val
372
+}
373
+
374
+// 设置redis key信息
375
+func SetAccountKeyInfo(key string, val string) bool {
376
+	pool := GetAccountRedisPool()
377
+	if pool == nil {
378
+		fmt.Println("get redis pool fail")
379
+		return false
380
+	}
381
+	rd := pool.Get()
382
+	defer rd.Close()
383
+
384
+	_, err := rd.Do("SET", key, val)
385
+	if err != nil {
386
+		log.Printf("设置 key[%s] 信息fail! err:%s", key, err)
387
+		return false
388
+	}
389
+
390
+	return true
391
+}

+ 27 - 3
utils/util.go

@@ -27,6 +27,7 @@ import (
27 27
 
28 28
 	"github.com/astaxie/beego"
29 29
 	"github.com/astaxie/beego/config"
30
+	"github.com/bitly/go-simplejson"
30 31
 )
31 32
 
32 33
 // StringToInt string to int
@@ -53,6 +54,12 @@ func Int64ToString(number int64) string {
53 54
 	return strconv.FormatInt(number, 10)
54 55
 }
55 56
 
57
+func JsonNumberToInt(itf interface{}) int {
58
+	str := itf.(json.Number).String()
59
+
60
+	return StringToInt(str)
61
+}
62
+
56 63
 // GetConf config
57 64
 func GetConf(key string, file string) string {
58 65
 	iniconf, err := config.NewConfig("ini", file)
@@ -240,7 +247,7 @@ func pKCS5UnPadding(origData []byte) []byte {
240 247
 	return origData[:(length - unpadding)]
241 248
 }
242 249
 
243
-//AesEncrypt aes加密函数,返回加密后的结果长度是16的倍数
250
+// AesEncrypt aes加密函数,返回加密后的结果长度是16的倍数
244 251
 func AesEncrypt(origData, key []byte) ([]byte, error) {
245 252
 	block, err := aes.NewCipher(key)
246 253
 	if err != nil {
@@ -257,7 +264,7 @@ func AesEncrypt(origData, key []byte) ([]byte, error) {
257 264
 	return crypted, nil
258 265
 }
259 266
 
260
-//AesDecrypt aes解密函数,传入解密内容长度必须是16的倍数
267
+// AesDecrypt aes解密函数,传入解密内容长度必须是16的倍数
261 268
 func AesDecrypt(crypted, key []byte) ([]byte, error) {
262 269
 	block, err := aes.NewCipher(key)
263 270
 	if err != nil {
@@ -300,4 +307,21 @@ func DecodeData(ts string, data string) (string, error) {
300 307
 	}
301 308
 
302 309
 	return string(de), nil
303
-}
310
+}
311
+
312
+// 加载json配置文件
313
+func LoadJsonFile(fileName string) *simplejson.Json {
314
+	data, err := ioutil.ReadFile(fileName)
315
+	if err != nil {
316
+		fmt.Println("load readFile", fileName, "err:", err)
317
+		return nil
318
+	}
319
+
320
+	j, err := simplejson.NewJson(data)
321
+	if err != nil {
322
+		fmt.Println("load unmarshal", fileName, "err:", err)
323
+		return nil
324
+	}
325
+
326
+	return j
327
+}