|
|
@@ -8,6 +8,79 @@ import { Encrypt, Decrypt } from '../../util/crypto/index.js';
|
|
8
|
8
|
import axios from 'axios';
|
|
9
|
9
|
import commonModel from '../../model/commonModel.js';
|
|
10
|
10
|
|
|
|
11
|
+// 验证IP地址格式是否有效
|
|
|
12
|
+function isValidIP(ip) {
|
|
|
13
|
+ if (!ip) return false;
|
|
|
14
|
+ // IPv4格式验证
|
|
|
15
|
+ const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
|
|
16
|
+ if (ipv4Regex.test(ip)) {
|
|
|
17
|
+ const parts = ip.split('.');
|
|
|
18
|
+ return parts.every(part => {
|
|
|
19
|
+ const num = parseInt(part, 10);
|
|
|
20
|
+ return num >= 0 && num <= 255;
|
|
|
21
|
+ });
|
|
|
22
|
+ }
|
|
|
23
|
+ // IPv6格式验证(简化版)
|
|
|
24
|
+ const ipv6Regex = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
|
|
|
25
|
+ return ipv6Regex.test(ip);
|
|
|
26
|
+}
|
|
|
27
|
+
|
|
|
28
|
+// 获取客户端真实IP地址的通用函数
|
|
|
29
|
+function getClientIP(ctx) {
|
|
|
30
|
+ // 检查所有可能的代理头
|
|
|
31
|
+ const proxyHeaders = [
|
|
|
32
|
+ 'x-forwarded-for',
|
|
|
33
|
+ 'x-real-ip',
|
|
|
34
|
+ 'x-client-ip',
|
|
|
35
|
+ 'x-forwarded',
|
|
|
36
|
+ 'forwarded-for',
|
|
|
37
|
+ 'x-cluster-client-ip',
|
|
|
38
|
+ 'proxy-client-ip',
|
|
|
39
|
+ 'cf-connecting-ip', // Cloudflare
|
|
|
40
|
+ 'true-client-ip', // Akamai and Cloudflare
|
|
|
41
|
+ 'fastly-client-ip', // Fastly
|
|
|
42
|
+ 'x-original-forwarded-for'
|
|
|
43
|
+ ];
|
|
|
44
|
+
|
|
|
45
|
+ let clientIP = null;
|
|
|
46
|
+
|
|
|
47
|
+ // 1. 首先检查所有代理头
|
|
|
48
|
+ for (const header of proxyHeaders) {
|
|
|
49
|
+ const value = ctx.request.headers[header];
|
|
|
50
|
+ if (value) {
|
|
|
51
|
+ // 处理可能的多个IP地址(取第一个,通常是最原始的客户端IP)
|
|
|
52
|
+ clientIP = value.split(',')[0].trim();
|
|
|
53
|
+ if (isValidIP(clientIP)) {
|
|
|
54
|
+ break;
|
|
|
55
|
+ }
|
|
|
56
|
+ }
|
|
|
57
|
+ }
|
|
|
58
|
+
|
|
|
59
|
+ // 2. 如果没有找到有效的代理头IP,尝试Koa的标准方法
|
|
|
60
|
+ if (!clientIP || !isValidIP(clientIP)) {
|
|
|
61
|
+ clientIP = ctx.ip || ctx.request.ip;
|
|
|
62
|
+ }
|
|
|
63
|
+
|
|
|
64
|
+ // 3. 如果还是没有,尝试socket
|
|
|
65
|
+ if (!clientIP || !isValidIP(clientIP)) {
|
|
|
66
|
+ clientIP = ctx.request.socket.remoteAddress;
|
|
|
67
|
+ }
|
|
|
68
|
+
|
|
|
69
|
+ // 处理IPv6格式
|
|
|
70
|
+ if (clientIP) {
|
|
|
71
|
+ // 处理IPv4映射的IPv6地址 (::ffff:127.0.0.1 格式)
|
|
|
72
|
+ if (clientIP.startsWith('::ffff:')) {
|
|
|
73
|
+ clientIP = clientIP.substring(7);
|
|
|
74
|
+ }
|
|
|
75
|
+ // 处理IPv6本地回环地址
|
|
|
76
|
+ else if (clientIP === '::1') {
|
|
|
77
|
+ clientIP = '127.0.0.1';
|
|
|
78
|
+ }
|
|
|
79
|
+ }
|
|
|
80
|
+
|
|
|
81
|
+ return clientIP || '0.0.0.0';
|
|
|
82
|
+}
|
|
|
83
|
+
|
|
11
|
84
|
//网站登录
|
|
12
|
85
|
export async function WebLogin (ctx){
|
|
13
|
86
|
const data1 = fs.readFileSync("./public/index.html");
|
|
|
@@ -16,7 +89,6 @@ export async function WebLogin (ctx){
|
|
16
|
89
|
|
|
17
|
90
|
//秒过网站登录
|
|
18
|
91
|
export async function WebLoginDo (ctx){
|
|
19
|
|
-
|
|
20
|
92
|
const param = {
|
|
21
|
93
|
Code: ctx.query.code,
|
|
22
|
94
|
State: ctx.query.state,
|
|
|
@@ -27,9 +99,8 @@ export async function WebLoginDo (ctx){
|
|
27
|
99
|
let result = {};
|
|
28
|
100
|
//网站跨用户跳转
|
|
29
|
101
|
if (param.Param){
|
|
30
|
|
-
|
|
31
|
102
|
console.log("param.Param:"+param.Param);
|
|
32
|
|
- param.Param=stringUtils.ReplaceAllString(param.Param,"@@@","+");
|
|
|
103
|
+ param.Param=param.Param.replace(/@@@/g, "+");
|
|
33
|
104
|
param.Param2= Decrypt(param.Param, config.urlSecrets.aes_key, config.urlSecrets.aes_iv);
|
|
34
|
105
|
console.log("param.Param2:"+param.Param2);
|
|
35
|
106
|
|
|
|
@@ -47,33 +118,25 @@ export async function WebLoginDo (ctx){
|
|
47
|
118
|
result = {errcode: 101};
|
|
48
|
119
|
}
|
|
49
|
120
|
else {
|
|
50
|
|
-
|
|
51
|
121
|
const code = param.Code;
|
|
52
|
|
- //console.log("code:"+code);
|
|
53
|
122
|
const url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' + config.wx.web_appid + '&secret=' + config.wx.web_appsecret + '&code=' + code + '&grant_type=authorization_code';
|
|
54
|
123
|
|
|
55
|
|
- //console.log("url:"+url);
|
|
56
|
124
|
try {
|
|
57
|
125
|
const response = await axios.get(url);
|
|
58
|
126
|
const json = response.data;
|
|
59
|
|
- //console.log("json1:"+htmlString);
|
|
60
|
127
|
if (json && json.openid) {
|
|
61
|
128
|
param.OpenID = json.openid;
|
|
62
|
129
|
if (json.unionid)
|
|
63
|
130
|
param.UnionID = json.unionid;
|
|
64
|
131
|
if (json.refresh_token)
|
|
65
|
132
|
param.refresh_token = json.refresh_token;
|
|
66
|
|
- //console.log("UnionID:"+param.UnionID);
|
|
67
|
133
|
|
|
68
|
134
|
if (param.UnionID == "oY_7p0ZSAQhfJc3Yg1Q8p4pAY-ns"
|
|
69
|
135
|
|| param.UnionID == "oY_7p0eMgy8NjIFnpbSpAtXamYRg"
|
|
70
|
136
|
|| param.UnionID == "oY_7p0ZqeajxewE0PSmP6X20AOtc"
|
|
71
|
137
|
|| process.env.NODE_ENV == "development") {
|
|
72
|
|
-
|
|
73
|
138
|
const userid = Encrypt(param.UnionID, config.urlSecrets.aes_key, config.urlSecrets.aes_iv);
|
|
74
|
139
|
ctx.cookies.set('test', userid, {maxAge: 365 * 24 * 60 * 60 * 1000});
|
|
75
|
|
- //console.log("UnionID2:"+userid);
|
|
76
|
|
-
|
|
77
|
140
|
}
|
|
78
|
141
|
|
|
79
|
142
|
result = {errcode: 10000};
|
|
|
@@ -86,18 +149,12 @@ export async function WebLoginDo (ctx){
|
|
86
|
149
|
}
|
|
87
|
150
|
}
|
|
88
|
151
|
|
|
89
|
|
- //console.log(result);
|
|
90
|
152
|
if (result.errcode!=10000){
|
|
91
|
|
-
|
|
92
|
153
|
const cookie=ctx.cookies.get("test");
|
|
93
|
|
- //console.log(cookie);
|
|
94
|
154
|
if (cookie=="+yqoClZSJfwPPQwow7K12IboznGF059HmGsK1lpS+4Y="
|
|
95
|
155
|
|| cookie=="ckQpqDsukHN49UgwpRdoYRC7uH1hTfXvhJ71hPzgyfM="
|
|
96
|
156
|
|| cookie=="IAdzqqCJ9ixjFGemUoqrJABRsF3EpvPgnIgGYFCWOhg="
|
|
97
|
157
|
|| process.env.NODE_ENV=="development") {
|
|
98
|
|
-
|
|
99
|
|
- //console.log("ctx.session.OpenID:"+ctx.session.OpenID);
|
|
100
|
|
- //测试用
|
|
101
|
158
|
if (param.UserID) {
|
|
102
|
159
|
// const userList = await miaoguo.GetUsersInfoByUserID(param);
|
|
103
|
160
|
// if (userList.length > 0) {
|
|
|
@@ -109,12 +166,14 @@ export async function WebLoginDo (ctx){
|
|
109
|
166
|
}
|
|
110
|
167
|
else if (result.errcode==102){
|
|
111
|
168
|
if (param.UserID) {
|
|
112
|
|
- const userList = await miaoguo.GetUsersInfoByUserID(param);
|
|
113
|
|
- if (userList.length > 0) {
|
|
114
|
|
- param.OpenID = userList[0].OpenID;
|
|
115
|
|
- param.UnionID = userList[0].UnionID;
|
|
116
|
|
- result.errcode = 10000;
|
|
117
|
|
- }
|
|
|
169
|
+ // 注释掉未定义模块的调用
|
|
|
170
|
+ // const userList = await miaoguo.GetUsersInfoByUserID(param);
|
|
|
171
|
+ // if (userList.length > 0) {
|
|
|
172
|
+ // param.OpenID = userList[0].OpenID;
|
|
|
173
|
+ // param.UnionID = userList[0].UnionID;
|
|
|
174
|
+ // result.errcode = 10000;
|
|
|
175
|
+ // }
|
|
|
176
|
+ console.log("警告: miaoguo 模块未定义,无法获取用户信息");
|
|
118
|
177
|
}
|
|
119
|
178
|
}
|
|
120
|
179
|
else if (ctx.session.OpenID) {
|
|
|
@@ -124,21 +183,23 @@ export async function WebLoginDo (ctx){
|
|
124
|
183
|
}
|
|
125
|
184
|
}
|
|
126
|
185
|
|
|
127
|
|
-
|
|
128
|
186
|
if (result.errcode==10000) {
|
|
129
|
187
|
ctx.session.OpenID = param.OpenID;
|
|
130
|
188
|
ctx.session.UnionID = param.UnionID;
|
|
131
|
189
|
|
|
132
|
|
- let userList = await miaoguo.GetUsersInfoByUnionID(param);
|
|
|
190
|
+ // 注释掉未定义模块的调用
|
|
|
191
|
+ // let userList = await miaoguo.GetUsersInfoByUnionID(param);
|
|
|
192
|
+ console.log("警告: miaoguo 模块未定义,无法获取用户信息");
|
|
|
193
|
+ let userList = []; // 创建一个空数组作为替代
|
|
133
|
194
|
|
|
134
|
195
|
//绑定用户则显示主帐号数据
|
|
135
|
|
- if (userList.length > 0 && userList[0].ParentUserID>0) {
|
|
136
|
|
- param.UserID=userList[0].ParentUserID;
|
|
137
|
|
- userList = await miaoguo.GetUsersInfoByUserID(param);
|
|
|
196
|
+ if (userList.length > 0 && userList[0] && userList[0].ParentUserID > 0) {
|
|
|
197
|
+ param.UserID = userList[0].ParentUserID;
|
|
|
198
|
+ // userList = await miaoguo.GetUsersInfoByUserID(param);
|
|
|
199
|
+ console.log("警告: miaoguo 模块未定义,无法获取用户信息");
|
|
138
|
200
|
}
|
|
139
|
201
|
|
|
140
|
202
|
if (userList.length > 0) {
|
|
141
|
|
-
|
|
142
|
203
|
const time3 = moment().format('YYYYMMDD');
|
|
143
|
204
|
const time4 = moment(userList[0].ProductServiceTime).format('YYYYMMDD');
|
|
144
|
205
|
|
|
|
@@ -147,23 +208,19 @@ export async function WebLoginDo (ctx){
|
|
147
|
208
|
isVisit=false;
|
|
148
|
209
|
}
|
|
149
|
210
|
if ((userList[0].IsTryOut==1 || userList[0].IsMember==1) && isVisit) {
|
|
150
|
|
-
|
|
151
|
211
|
const data1 = fs.readFileSync("./public/mg/main.html");
|
|
152
|
|
-
|
|
153
|
|
-
|
|
154
|
212
|
ctx.body = data1.toString();
|
|
155
|
213
|
}
|
|
156
|
214
|
else{
|
|
157
|
|
- ctx.body ="您尚且不是“秒过学习”会员或者会员有效期已经过期,请到小程序中去申请或续费。";
|
|
|
215
|
+ ctx.body ="您尚且不是\"秒过学习\"会员或者会员有效期已经过期,请到小程序中去申请或续费。";
|
|
158
|
216
|
}
|
|
159
|
217
|
}
|
|
160
|
|
- else{
|
|
161
|
|
- ctx.body ="您尚且不是“秒过学习”用户,请先到微信小程序中登录授权。";
|
|
162
|
|
- }
|
|
|
218
|
+ else{
|
|
|
219
|
+ ctx.body ="您尚且不是\"秒过学习\"用户,请先到微信小程序中登录授权。";
|
|
|
220
|
+ }
|
|
163
|
221
|
}
|
|
164
|
222
|
else
|
|
165
|
223
|
ctx.body ="<html><body>请重新<a href='https://www.kylx365.com/miaoguo'>登录</a></body></html>";
|
|
166
|
|
-
|
|
167
|
224
|
}
|
|
168
|
225
|
|
|
169
|
226
|
//网站登出
|
|
|
@@ -185,22 +242,21 @@ export async function Kylx365DBAdmin(ctx) {
|
|
185
|
242
|
|
|
186
|
243
|
const allowedIP = '192.168.1.100'; // 您的本地IP
|
|
187
|
244
|
const clientToken = ctx.req.headers['x-auth-token'];
|
|
188
|
|
- let clientIP = ctx.ip || ctx.request.ip ||
|
|
189
|
|
- (ctx.request.headers['x-forwarded-for'] || '').split(',')[0] ||
|
|
190
|
|
- ctx.request.socket.remoteAddress;
|
|
191
|
|
-
|
|
192
|
|
- // 处理IPv6格式的IP地址
|
|
193
|
|
- if (clientIP) {
|
|
194
|
|
- // 处理IPv4映射的IPv6地址 (::ffff:127.0.0.1 格式)
|
|
195
|
|
- if (clientIP.startsWith('::ffff:')) {
|
|
196
|
|
- clientIP = clientIP.substring(7); // 移除 ::ffff: 前缀
|
|
197
|
|
- }
|
|
198
|
|
- // 如果是IPv6的本地回环地址 (::1),转换为IPv4的本地回环地址
|
|
199
|
|
- else if (clientIP === '::1') {
|
|
200
|
|
- clientIP = '127.0.0.1';
|
|
201
|
|
- }
|
|
202
|
|
- }
|
|
203
|
|
- console.log("clientIP:"+clientIP);
|
|
|
245
|
+
|
|
|
246
|
+ // 使用增强的IP获取函数
|
|
|
247
|
+ let clientIP = getClientIP(ctx);
|
|
|
248
|
+
|
|
|
249
|
+ // 记录详细的IP信息用于调试
|
|
|
250
|
+ console.log('IP来源信息:', {
|
|
|
251
|
+ 'x-forwarded-for': ctx.request.headers['x-forwarded-for'],
|
|
|
252
|
+ 'x-real-ip': ctx.request.headers['x-real-ip'],
|
|
|
253
|
+ 'ctx.ip': ctx.ip,
|
|
|
254
|
+ 'socket.remoteAddress': ctx.request.socket.remoteAddress,
|
|
|
255
|
+ '最终使用的IP': clientIP,
|
|
|
256
|
+ '所有请求头': ctx.request.headers
|
|
|
257
|
+ });
|
|
|
258
|
+
|
|
|
259
|
+ console.log("clientIP:" + clientIP);
|
|
204
|
260
|
let data = "";
|
|
205
|
261
|
|
|
206
|
262
|
if (clientIP === allowedIP || clientIP=="127.0.0.1") {
|
|
|
@@ -238,25 +294,12 @@ export async function RunKylx365DBSql(ctx) {
|
|
238
|
294
|
IsCompleteField:ctx.request.body.IsCompleteField || false,
|
|
239
|
295
|
};
|
|
240
|
296
|
|
|
241
|
|
- // 获取客户端IP地址
|
|
242
|
|
- let clientIP = ctx.ip || ctx.request.ip ||
|
|
243
|
|
- (ctx.request.headers['x-forwarded-for'] || '').split(',')[0] ||
|
|
244
|
|
- ctx.request.socket.remoteAddress;
|
|
245
|
|
-
|
|
246
|
|
- // 处理IPv6格式的IP地址
|
|
247
|
|
- if (clientIP) {
|
|
248
|
|
- // 处理IPv4映射的IPv6地址 (::ffff:127.0.0.1 格式)
|
|
249
|
|
- if (clientIP.startsWith('::ffff:')) {
|
|
250
|
|
- clientIP = clientIP.substring(7); // 移除 ::ffff: 前缀
|
|
251
|
|
- }
|
|
252
|
|
- // 如果是IPv6的本地回环地址 (::1),转换为IPv4的本地回环地址
|
|
253
|
|
- else if (clientIP === '::1') {
|
|
254
|
|
- clientIP = '127.0.0.1';
|
|
255
|
|
- }
|
|
256
|
|
- }
|
|
|
297
|
+ // 使用增强的IP获取函数
|
|
|
298
|
+ let clientIP = getClientIP(ctx);
|
|
257
|
299
|
|
|
258
|
300
|
console.log("客户端IP: " + clientIP);
|
|
259
|
301
|
console.log(param.SQL);
|
|
|
302
|
+
|
|
260
|
303
|
// 获取第一个分号前的SQL语句
|
|
261
|
304
|
const firstStatement = param.SQL.split(';')[0].trim();
|
|
262
|
305
|
|