sumor 3.0.5 → 3.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server/controllers/tokenRefreshController.d.ts.map +1 -1
- package/dist/server/controllers/tokenRefreshController.js +48 -27
- package/dist/server/controllers/tokenRefreshController.js.map +1 -1
- package/dist/server/index.d.ts +7 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +6 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/middlewares/isLoggedMiddleware.d.ts +15 -0
- package/dist/server/middlewares/isLoggedMiddleware.d.ts.map +1 -0
- package/dist/server/middlewares/isLoggedMiddleware.js +35 -0
- package/dist/server/middlewares/isLoggedMiddleware.js.map +1 -0
- package/dist/server/middlewares/isVerifiedMiddleware.d.ts +16 -0
- package/dist/server/middlewares/isVerifiedMiddleware.d.ts.map +1 -0
- package/dist/server/middlewares/isVerifiedMiddleware.js +44 -0
- package/dist/server/middlewares/isVerifiedMiddleware.js.map +1 -0
- package/dist/server/utils/authUtils.d.ts +7 -1
- package/dist/server/utils/authUtils.d.ts.map +1 -1
- package/dist/server/utils/authUtils.js +14 -13
- package/dist/server/utils/authUtils.js.map +1 -1
- package/package.json +1 -1
- package/dist/server/controllers/getAuthorizeUrlController.d.ts +0 -9
- package/dist/server/controllers/getAuthorizeUrlController.d.ts.map +0 -1
- package/dist/server/controllers/getAuthorizeUrlController.js +0 -80
- package/dist/server/controllers/getAuthorizeUrlController.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokenRefreshController.d.ts","sourceRoot":"","sources":["../../../server/controllers/tokenRefreshController.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"tokenRefreshController.d.ts","sourceRoot":"","sources":["../../../server/controllers/tokenRefreshController.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAQ3C,wBAA8B,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,+CAiG/E"}
|
|
@@ -15,6 +15,7 @@ const oauthTokenUtils_1 = require("../utils/oauthTokenUtils");
|
|
|
15
15
|
const tokenModel_1 = require("../models/tokenModel");
|
|
16
16
|
const config_1 = require("../utils/config");
|
|
17
17
|
const authorizationUrlGenerator_1 = require("../utils/authorizationUrlGenerator");
|
|
18
|
+
const authUtils_1 = require("../utils/authUtils");
|
|
18
19
|
async function tokenRefreshController(req, res) {
|
|
19
20
|
const config = (0, config_1.getOAuthConfig)();
|
|
20
21
|
const oauthAuthorizeUrl = (0, authorizationUrlGenerator_1.generateAuthorizationUrl)();
|
|
@@ -24,45 +25,65 @@ async function tokenRefreshController(req, res) {
|
|
|
24
25
|
let message = '未登录';
|
|
25
26
|
let user = null;
|
|
26
27
|
try {
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (!refreshToken) {
|
|
32
|
-
refreshToken = req.cookies?.refresh_token;
|
|
33
|
-
}
|
|
34
|
-
// 如果有有效的 refreshToken,进行刷新
|
|
35
|
-
if (refreshToken) {
|
|
36
|
-
// 使用 OAuthService 调用 ITS API
|
|
37
|
-
const oauthService = new oauthService_1.default();
|
|
38
|
-
const tokenData = await oauthService.refreshAccessToken(refreshToken);
|
|
39
|
-
// 使用公用的 token 设置函数
|
|
40
|
-
// 设置新的 accessToken
|
|
41
|
-
(0, oauthTokenUtils_1.setOAuthTokenCookie)(res, tokenData.accessToken, tokenData.expiresIn, 'access');
|
|
42
|
-
// 如果返回了新的 refreshToken,也设置上
|
|
43
|
-
// PUT /token 通常不返回新的 refreshToken,但为了保险起见检查
|
|
44
|
-
if (tokenData.refreshToken && tokenData.refreshToken !== refreshToken) {
|
|
45
|
-
(0, oauthTokenUtils_1.setOAuthTokenCookie)(res, tokenData.refreshToken, 2592000, 'refresh'); // 30 days
|
|
46
|
-
}
|
|
47
|
-
// 验证新的 accessToken 获取用户信息
|
|
28
|
+
// 第一步:先从 Cookie 中获取并验证 access_token
|
|
29
|
+
const accessToken = (0, authUtils_1.getAccessToken)(req);
|
|
30
|
+
const tokenModel = (0, tokenModel_1.getTokenModel)();
|
|
31
|
+
if (accessToken) {
|
|
48
32
|
try {
|
|
49
|
-
|
|
50
|
-
const claims = await tokenModel.verify(
|
|
33
|
+
// 尝试验证现有的 access_token
|
|
34
|
+
const claims = await tokenModel.verify(accessToken);
|
|
51
35
|
if (claims.sub) {
|
|
36
|
+
// access_token 有效且未过期,无需刷新
|
|
52
37
|
user = {
|
|
53
38
|
id: claims.sub,
|
|
54
39
|
isVerified: claims.isVerified || 0,
|
|
55
40
|
roles: claims.roles || '',
|
|
56
41
|
permissions: claims.permissions || ''
|
|
57
42
|
};
|
|
43
|
+
message = 'Token 仍然有效';
|
|
58
44
|
}
|
|
59
45
|
}
|
|
60
46
|
catch (error) {
|
|
61
|
-
//
|
|
62
|
-
console.
|
|
47
|
+
// access_token 已过期或无效,继续执行刷新流程
|
|
48
|
+
console.log('Access token 已过期或无效,准备刷新');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// 如果 access_token 无效,进行第二步刷新
|
|
52
|
+
if (!user) {
|
|
53
|
+
// 第二步:从 Cookie 中获取 refreshToken 进行刷新
|
|
54
|
+
const refreshToken = (0, authUtils_1.getRefreshToken)(req);
|
|
55
|
+
// 如果有有效的 refreshToken,进行刷新
|
|
56
|
+
if (refreshToken) {
|
|
57
|
+
// 使用 OAuthService 调用 ITS API
|
|
58
|
+
const oauthService = new oauthService_1.default();
|
|
59
|
+
const tokenData = await oauthService.refreshAccessToken(refreshToken);
|
|
60
|
+
// 使用公用的 token 设置函数
|
|
61
|
+
// 设置新的 accessToken
|
|
62
|
+
(0, oauthTokenUtils_1.setOAuthTokenCookie)(res, tokenData.accessToken, tokenData.expiresIn, 'access');
|
|
63
|
+
// 如果返回了新的 refreshToken,也设置上
|
|
64
|
+
// PUT /token 通常不返回新的 refreshToken,但为了保险起见检查
|
|
65
|
+
if (tokenData.refreshToken && tokenData.refreshToken !== refreshToken) {
|
|
66
|
+
(0, oauthTokenUtils_1.setOAuthTokenCookie)(res, tokenData.refreshToken, 2592000, 'refresh'); // 30 days
|
|
67
|
+
}
|
|
68
|
+
// 验证新的 accessToken 获取用户信息
|
|
69
|
+
try {
|
|
70
|
+
const claims = await tokenModel.verify(tokenData.accessToken);
|
|
71
|
+
if (claims.sub) {
|
|
72
|
+
user = {
|
|
73
|
+
id: claims.sub,
|
|
74
|
+
isVerified: claims.isVerified || 0,
|
|
75
|
+
roles: claims.roles || '',
|
|
76
|
+
permissions: claims.permissions || ''
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
// Token 验证失败,返回 null user
|
|
82
|
+
console.error('Failed to verify new token:', error);
|
|
83
|
+
}
|
|
84
|
+
// 更新消息为成功登录状态
|
|
85
|
+
message = 'Token 刷新成功';
|
|
63
86
|
}
|
|
64
|
-
// 更新消息为成功登录状态
|
|
65
|
-
message = 'Token 刷新成功';
|
|
66
87
|
}
|
|
67
88
|
}
|
|
68
89
|
catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokenRefreshController.js","sourceRoot":"","sources":["../../../server/controllers/tokenRefreshController.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;
|
|
1
|
+
{"version":3,"file":"tokenRefreshController.js","sourceRoot":"","sources":["../../../server/controllers/tokenRefreshController.ts"],"names":[],"mappings":"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"}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
* 统一管理 OAuth 权限同步、JWT 用户加载和 OAuth 路由注册
|
|
4
4
|
*/
|
|
5
5
|
import { Express } from 'express';
|
|
6
|
+
import { loadJwtUserMiddleware } from './middlewares/loadJwtUserMiddleware';
|
|
7
|
+
import { isLoggedMiddleware } from './middlewares/isLoggedMiddleware';
|
|
8
|
+
import { isVerifiedMiddleware } from './middlewares/isVerifiedMiddleware';
|
|
6
9
|
import type { PermissionConfig } from './types/oauth';
|
|
7
10
|
/**
|
|
8
11
|
* 初始化 Sumor OAuth 集成
|
|
@@ -12,4 +15,8 @@ import type { PermissionConfig } from './types/oauth';
|
|
|
12
15
|
* @param permissionConfig 权限配置 { permissions, permissionLabels }
|
|
13
16
|
*/
|
|
14
17
|
export default function setupSumor(app: Express, permissionConfig: PermissionConfig): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* 导出中间件供 client 使用
|
|
20
|
+
*/
|
|
21
|
+
export { loadJwtUserMiddleware, isLoggedMiddleware, isVerifiedMiddleware };
|
|
15
22
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../server/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../server/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAGjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAA;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAA;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAA;AAEzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAiBrD;;;;;;GAMG;AACH,wBAA8B,UAAU,CACtC,GAAG,EAAE,OAAO,EACZ,gBAAgB,EAAE,gBAAgB,GACjC,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED;;GAEG;AACH,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,CAAA"}
|
package/dist/server/index.js
CHANGED
|
@@ -7,10 +7,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
7
7
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
8
|
};
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.isVerifiedMiddleware = exports.isLoggedMiddleware = exports.loadJwtUserMiddleware = void 0;
|
|
10
11
|
exports.default = setupSumor;
|
|
11
12
|
const oauthService_1 = __importDefault(require("./services/oauthService"));
|
|
12
13
|
const routes_1 = __importDefault(require("./routes"));
|
|
13
14
|
const loadJwtUserMiddleware_1 = require("./middlewares/loadJwtUserMiddleware");
|
|
15
|
+
Object.defineProperty(exports, "loadJwtUserMiddleware", { enumerable: true, get: function () { return loadJwtUserMiddleware_1.loadJwtUserMiddleware; } });
|
|
16
|
+
const isLoggedMiddleware_1 = require("./middlewares/isLoggedMiddleware");
|
|
17
|
+
Object.defineProperty(exports, "isLoggedMiddleware", { enumerable: true, get: function () { return isLoggedMiddleware_1.isLoggedMiddleware; } });
|
|
18
|
+
const isVerifiedMiddleware_1 = require("./middlewares/isVerifiedMiddleware");
|
|
19
|
+
Object.defineProperty(exports, "isVerifiedMiddleware", { enumerable: true, get: function () { return isVerifiedMiddleware_1.isVerifiedMiddleware; } });
|
|
14
20
|
const config_1 = require("./utils/config");
|
|
15
21
|
/**
|
|
16
22
|
* 初始化 Sumor OAuth 权限同步
|
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/index.ts"],"names":[],"mappings":";AAAA;;;GAGG
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;AAiCH,6BA4BC;AA1DD,2EAAkD;AAClD,sDAAkC;AAClC,+EAA2E;AA6DlE,sGA7DA,6CAAqB,OA6DA;AA5D9B,yEAAqE;AA4DrC,mGA5DvB,uCAAkB,OA4DuB;AA3DlD,6EAAyE;AA2DrB,qGA3D3C,2CAAoB,OA2D2C;AA1DxE,2CAAsD;AAGtD;;;GAGG;AACH,KAAK,UAAU,0BAA0B,CAAC,gBAAkC;IAC1E,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,IAAI,sBAAY,EAAE,CAAA;QAEvC,iBAAiB;QACjB,MAAO,YAAoB,CAAC,iBAAiB,CAAC,gBAAgB,CAAC,CAAA;IACjE,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,iBAAiB;IACnB,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACY,KAAK,UAAU,UAAU,CACtC,GAAY,EACZ,gBAAkC;IAElC,IAAI,CAAC;QACH,0BAA0B;QAC1B,IAAA,8BAAqB,GAAE,CAGtB;QAAC,GAAW,CAAC,KAAK,GAAG,IAAI,sBAAY,EAAE,CAAA;QAExC,oBAAoB;QACpB,MAAM,0BAA0B,CAAC,gBAAgB,CAAC,CAAA;QAElD,oBAAoB;QACpB,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,6CAAqB,CAAC,CAAA;QAEtC,oCAAoC;QACpC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,GAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;YACtC,GAAG,CAAC,KAAK,GAAI,GAAW,CAAC,KAAK,CAAA;YAC9B,IAAI,EAAE,CAAA;QACR,CAAC,CAAC,CAAA;QAEF,iBAAiB;QACjB,GAAG,CAAC,GAAG,CAAC,YAAY,EAAE,gBAAW,CAAC,CAAA;IACpC,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 检查用户登录中间件
|
|
3
|
+
* 检查用户是否已登录 (jwtUser 存在)
|
|
4
|
+
* 如果未登录则返回 401 Unauthorized
|
|
5
|
+
*/
|
|
6
|
+
import { Response, NextFunction } from 'express';
|
|
7
|
+
/**
|
|
8
|
+
* 检查用户是否已登录
|
|
9
|
+
* @param req Express Request 对象,应包含 jwtUser(由 loadJwtUserMiddleware 注入)
|
|
10
|
+
* @param res Express Response 对象
|
|
11
|
+
* @param next 下一个中间件或路由处理器
|
|
12
|
+
*/
|
|
13
|
+
export declare function isLoggedMiddleware(req: any, res: Response, next: NextFunction): void;
|
|
14
|
+
export default isLoggedMiddleware;
|
|
15
|
+
//# sourceMappingURL=isLoggedMiddleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isLoggedMiddleware.d.ts","sourceRoot":"","sources":["../../../server/middlewares/isLoggedMiddleware.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAEhD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CAkBpF;AAED,eAAe,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 检查用户登录中间件
|
|
4
|
+
* 检查用户是否已登录 (jwtUser 存在)
|
|
5
|
+
* 如果未登录则返回 401 Unauthorized
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.isLoggedMiddleware = isLoggedMiddleware;
|
|
9
|
+
/**
|
|
10
|
+
* 检查用户是否已登录
|
|
11
|
+
* @param req Express Request 对象,应包含 jwtUser(由 loadJwtUserMiddleware 注入)
|
|
12
|
+
* @param res Express Response 对象
|
|
13
|
+
* @param next 下一个中间件或路由处理器
|
|
14
|
+
*/
|
|
15
|
+
function isLoggedMiddleware(req, res, next) {
|
|
16
|
+
try {
|
|
17
|
+
// 检查用户是否存在
|
|
18
|
+
if (!req.jwtUser || !req.jwtUser.userId) {
|
|
19
|
+
res.status(401).json({
|
|
20
|
+
code: 'UNAUTHORIZED',
|
|
21
|
+
message: '需要登录'
|
|
22
|
+
});
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
next();
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
res.status(500).json({
|
|
29
|
+
code: 'SERVER_ERROR',
|
|
30
|
+
message: '服务器内部错误'
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
exports.default = isLoggedMiddleware;
|
|
35
|
+
//# sourceMappingURL=isLoggedMiddleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isLoggedMiddleware.js","sourceRoot":"","sources":["../../../server/middlewares/isLoggedMiddleware.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AAUH,gDAkBC;AAxBD;;;;;GAKG;AACH,SAAgB,kBAAkB,CAAC,GAAQ,EAAE,GAAa,EAAE,IAAkB;IAC5E,IAAI,CAAC;QACH,WAAW;QACX,IAAI,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACxC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,IAAI,EAAE,cAAc;gBACpB,OAAO,EAAE,MAAM;aAChB,CAAC,CAAA;YACF,OAAM;QACR,CAAC;QAED,IAAI,EAAE,CAAA;IACR,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACnB,IAAI,EAAE,cAAc;YACpB,OAAO,EAAE,SAAS;SACnB,CAAC,CAAA;IACJ,CAAC;AACH,CAAC;AAED,kBAAe,kBAAkB,CAAA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 验证用户身份中间件
|
|
3
|
+
* 检查用户是否已认证 (isVerified === 1)
|
|
4
|
+
* 如果未认证则返回 403 Forbidden
|
|
5
|
+
*/
|
|
6
|
+
import { Response, NextFunction } from 'express';
|
|
7
|
+
/**
|
|
8
|
+
* 检查用户是否已通过身份认证
|
|
9
|
+
* 通常需要与 isLoggedMiddleware 一起使用
|
|
10
|
+
* @param req Express Request 对象,应包含 jwtUser(由 loadJwtUserMiddleware 注入)
|
|
11
|
+
* @param res Express Response 对象
|
|
12
|
+
* @param next 下一个中间件或路由处理器
|
|
13
|
+
*/
|
|
14
|
+
export declare function isVerifiedMiddleware(req: any, res: Response, next: NextFunction): void;
|
|
15
|
+
export default isVerifiedMiddleware;
|
|
16
|
+
//# sourceMappingURL=isVerifiedMiddleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isVerifiedMiddleware.d.ts","sourceRoot":"","sources":["../../../server/middlewares/isVerifiedMiddleware.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAEhD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,GAAG,IAAI,CA2BtF;AAED,eAAe,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 验证用户身份中间件
|
|
4
|
+
* 检查用户是否已认证 (isVerified === 1)
|
|
5
|
+
* 如果未认证则返回 403 Forbidden
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.isVerifiedMiddleware = isVerifiedMiddleware;
|
|
9
|
+
/**
|
|
10
|
+
* 检查用户是否已通过身份认证
|
|
11
|
+
* 通常需要与 isLoggedMiddleware 一起使用
|
|
12
|
+
* @param req Express Request 对象,应包含 jwtUser(由 loadJwtUserMiddleware 注入)
|
|
13
|
+
* @param res Express Response 对象
|
|
14
|
+
* @param next 下一个中间件或路由处理器
|
|
15
|
+
*/
|
|
16
|
+
function isVerifiedMiddleware(req, res, next) {
|
|
17
|
+
try {
|
|
18
|
+
// 检查用户是否存在
|
|
19
|
+
if (!req.jwtUser) {
|
|
20
|
+
res.status(401).json({
|
|
21
|
+
code: 'UNAUTHORIZED',
|
|
22
|
+
message: '未认证,请先登录'
|
|
23
|
+
});
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
// 检查用户是否已认证
|
|
27
|
+
if (req.jwtUser.isVerified !== 1) {
|
|
28
|
+
res.status(403).json({
|
|
29
|
+
code: 'FORBIDDEN',
|
|
30
|
+
message: '没有权限访问,用户未通过认证'
|
|
31
|
+
});
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
next();
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
res.status(500).json({
|
|
38
|
+
code: 'SERVER_ERROR',
|
|
39
|
+
message: '服务器内部错误'
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.default = isVerifiedMiddleware;
|
|
44
|
+
//# sourceMappingURL=isVerifiedMiddleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isVerifiedMiddleware.js","sourceRoot":"","sources":["../../../server/middlewares/isVerifiedMiddleware.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AAWH,oDA2BC;AAlCD;;;;;;GAMG;AACH,SAAgB,oBAAoB,CAAC,GAAQ,EAAE,GAAa,EAAE,IAAkB;IAC9E,IAAI,CAAC;QACH,WAAW;QACX,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;YACjB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,IAAI,EAAE,cAAc;gBACpB,OAAO,EAAE,UAAU;aACpB,CAAC,CAAA;YACF,OAAM;QACR,CAAC;QAED,YAAY;QACZ,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,KAAK,CAAC,EAAE,CAAC;YACjC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,gBAAgB;aAC1B,CAAC,CAAA;YACF,OAAM;QACR,CAAC;QAED,IAAI,EAAE,CAAA;IACR,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACnB,IAAI,EAAE,cAAc;YACpB,OAAO,EAAE,SAAS;SACnB,CAAC,CAAA;IACJ,CAAC;AACH,CAAC;AAED,kBAAe,oBAAoB,CAAA"}
|
|
@@ -7,9 +7,15 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export declare function parseCookies(cookieHeader?: string): Record<string, string>;
|
|
9
9
|
/**
|
|
10
|
-
* 从 Cookie
|
|
10
|
+
* 从 Cookie 中获取 Access Token
|
|
11
11
|
* @param req Express 请求对象
|
|
12
12
|
* @returns Token 字符串,如果未找到返回 null
|
|
13
13
|
*/
|
|
14
14
|
export declare function getAccessToken(req: any): string | null;
|
|
15
|
+
/**
|
|
16
|
+
* 从 Cookie 中获取 Refresh Token
|
|
17
|
+
* @param req Express 请求对象
|
|
18
|
+
* @returns Refresh Token 或 null
|
|
19
|
+
*/
|
|
20
|
+
export declare function getRefreshToken(req: any): string | null;
|
|
15
21
|
//# sourceMappingURL=authUtils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authUtils.d.ts","sourceRoot":"","sources":["../../../server/utils/authUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,wBAAgB,YAAY,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAgB1E;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"authUtils.d.ts","sourceRoot":"","sources":["../../../server/utils/authUtils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,wBAAgB,YAAY,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAgB1E;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI,CAItD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI,CAIvD"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.parseCookies = parseCookies;
|
|
8
8
|
exports.getAccessToken = getAccessToken;
|
|
9
|
+
exports.getRefreshToken = getRefreshToken;
|
|
9
10
|
/**
|
|
10
11
|
* 解析 Cookie 字符串
|
|
11
12
|
*/
|
|
@@ -24,23 +25,23 @@ function parseCookies(cookieHeader) {
|
|
|
24
25
|
return cookies;
|
|
25
26
|
}
|
|
26
27
|
/**
|
|
27
|
-
* 从 Cookie
|
|
28
|
+
* 从 Cookie 中获取 Access Token
|
|
28
29
|
* @param req Express 请求对象
|
|
29
30
|
* @returns Token 字符串,如果未找到返回 null
|
|
30
31
|
*/
|
|
31
32
|
function getAccessToken(req) {
|
|
32
|
-
//
|
|
33
|
+
// 仅从 Cookie 获取 access_token
|
|
33
34
|
const cookies = parseCookies(req.headers?.cookie);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return null;
|
|
35
|
+
return cookies.access_token || null;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 从 Cookie 中获取 Refresh Token
|
|
39
|
+
* @param req Express 请求对象
|
|
40
|
+
* @returns Refresh Token 或 null
|
|
41
|
+
*/
|
|
42
|
+
function getRefreshToken(req) {
|
|
43
|
+
// 从 Cookie 获取 refresh_token
|
|
44
|
+
const cookies = parseCookies(req.headers?.cookie);
|
|
45
|
+
return cookies.refresh_token || null;
|
|
45
46
|
}
|
|
46
47
|
//# sourceMappingURL=authUtils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authUtils.js","sourceRoot":"","sources":["../../../server/utils/authUtils.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAKH,oCAgBC;AAOD,
|
|
1
|
+
{"version":3,"file":"authUtils.js","sourceRoot":"","sources":["../../../server/utils/authUtils.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAKH,oCAgBC;AAOD,wCAIC;AAOD,0CAIC;AAzCD;;GAEG;AACH,SAAgB,YAAY,CAAC,YAAqB;IAChD,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,EAAE,CAAA;IACX,CAAC;IAED,MAAM,OAAO,GAA2B,EAAE,CAAA;IAE1C,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;QACvC,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QACzC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;QACnC,IAAI,IAAI,IAAI,KAAK,EAAE,CAAC;YAClB,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAA;QAClD,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;;GAIG;AACH,SAAgB,cAAc,CAAC,GAAQ;IACrC,4BAA4B;IAC5B,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IACjD,OAAO,OAAO,CAAC,YAAY,IAAI,IAAI,CAAA;AACrC,CAAC;AAED;;;;GAIG;AACH,SAAgB,eAAe,CAAC,GAAQ;IACtC,4BAA4B;IAC5B,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IACjD,OAAO,OAAO,CAAC,aAAa,IAAI,IAAI,CAAA;AACtC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 获取授权 URL 控制器
|
|
3
|
-
* GET /api/oauth/authorize
|
|
4
|
-
*
|
|
5
|
-
* 返回跳转到 ITS 的授权 URL,前端将用此 URL 进行重定向
|
|
6
|
-
*/
|
|
7
|
-
import { Request, Response } from 'express';
|
|
8
|
-
export default function getAuthorizeUrlController(req: Request, res: Response): void;
|
|
9
|
-
//# sourceMappingURL=getAuthorizeUrlController.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"getAuthorizeUrlController.d.ts","sourceRoot":"","sources":["../../../server/controllers/getAuthorizeUrlController.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAgE3C,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,QAgB5E"}
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* 获取授权 URL 控制器
|
|
4
|
-
* GET /api/oauth/authorize
|
|
5
|
-
*
|
|
6
|
-
* 返回跳转到 ITS 的授权 URL,前端将用此 URL 进行重定向
|
|
7
|
-
*/
|
|
8
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.default = getAuthorizeUrlController;
|
|
13
|
-
const crypto_1 = __importDefault(require("crypto"));
|
|
14
|
-
const config_1 = require("../utils/config");
|
|
15
|
-
/**
|
|
16
|
-
* 生成 PKCE code_challenge 和 code_verifier
|
|
17
|
-
*/
|
|
18
|
-
function generateCodeChallenge() {
|
|
19
|
-
const codeVerifier = crypto_1.default.randomBytes(32).toString('hex');
|
|
20
|
-
const challenge = crypto_1.default
|
|
21
|
-
.createHash('sha256')
|
|
22
|
-
.update(codeVerifier)
|
|
23
|
-
.digest('base64')
|
|
24
|
-
.replace(/\+/g, '-')
|
|
25
|
-
.replace(/\//g, '_')
|
|
26
|
-
.replace(/=/g, '');
|
|
27
|
-
return {
|
|
28
|
-
codeChallenge: challenge,
|
|
29
|
-
codeVerifier: codeVerifier
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* 生成随机 state 参数
|
|
34
|
-
*/
|
|
35
|
-
function generateState() {
|
|
36
|
-
return crypto_1.default.randomBytes(32).toString('hex');
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* 生成授权 URL
|
|
40
|
-
* RFC 6749 §4.1.1,支持 PKCE(RFC 7636)用于增强安全性
|
|
41
|
-
*/
|
|
42
|
-
function generateAuthorizationUrl() {
|
|
43
|
-
const oauthConfig = (0, config_1.getOAuthConfig)();
|
|
44
|
-
const { codeChallenge, codeVerifier } = generateCodeChallenge();
|
|
45
|
-
const uri = oauthConfig.redirectUri;
|
|
46
|
-
if (!uri || uri.trim() === '') {
|
|
47
|
-
throw new Error('redirectUri 为空或未配置,无法生成授权 URL');
|
|
48
|
-
}
|
|
49
|
-
const randomState = generateState();
|
|
50
|
-
const encryptedState = Buffer.from(codeVerifier).toString('base64') + ':' + randomState;
|
|
51
|
-
const params = new URLSearchParams({
|
|
52
|
-
clientKey: oauthConfig.clientKey,
|
|
53
|
-
redirectUri: uri,
|
|
54
|
-
responseType: 'code',
|
|
55
|
-
scope: 'profile',
|
|
56
|
-
state: encryptedState,
|
|
57
|
-
codeChallenge: codeChallenge,
|
|
58
|
-
codeChallengeMethod: 'S256'
|
|
59
|
-
});
|
|
60
|
-
const authUrl = `${oauthConfig.baseUrl}/authorize?${params.toString()}`;
|
|
61
|
-
return authUrl;
|
|
62
|
-
}
|
|
63
|
-
function getAuthorizeUrlController(req, res) {
|
|
64
|
-
try {
|
|
65
|
-
const authUrl = generateAuthorizationUrl();
|
|
66
|
-
res.json({
|
|
67
|
-
code: 'OK',
|
|
68
|
-
data: {
|
|
69
|
-
authUrl
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
catch (error) {
|
|
74
|
-
res.status(500).json({
|
|
75
|
-
code: 'ERROR',
|
|
76
|
-
message: error.message
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
//# sourceMappingURL=getAuthorizeUrlController.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"getAuthorizeUrlController.js","sourceRoot":"","sources":["../../../server/controllers/getAuthorizeUrlController.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;AAmEH,4CAgBC;AAjFD,oDAA2B;AAE3B,4CAAgD;AAEhD;;GAEG;AACH,SAAS,qBAAqB;IAI5B,MAAM,YAAY,GAAG,gBAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3D,MAAM,SAAS,GAAG,gBAAM;SACrB,UAAU,CAAC,QAAQ,CAAC;SACpB,MAAM,CAAC,YAAY,CAAC;SACpB,MAAM,CAAC,QAAQ,CAAC;SAChB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IAEpB,OAAO;QACL,aAAa,EAAE,SAAS;QACxB,YAAY,EAAE,YAAY;KAC3B,CAAA;AACH,CAAC;AAED;;GAEG;AACH,SAAS,aAAa;IACpB,OAAO,gBAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;AAC/C,CAAC;AAED;;;GAGG;AACH,SAAS,wBAAwB;IAC/B,MAAM,WAAW,GAAG,IAAA,uBAAc,GAAE,CAAA;IACpC,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,GAAG,qBAAqB,EAAE,CAAA;IAE/D,MAAM,GAAG,GAAG,WAAW,CAAC,WAAW,CAAA;IAEnC,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAA;IAClD,CAAC;IAED,MAAM,WAAW,GAAG,aAAa,EAAE,CAAA;IACnC,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,GAAG,GAAG,WAAW,CAAA;IAEvF,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QACjC,SAAS,EAAE,WAAW,CAAC,SAAS;QAChC,WAAW,EAAE,GAAG;QAChB,YAAY,EAAE,MAAM;QACpB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,cAAc;QACrB,aAAa,EAAE,aAAa;QAC5B,mBAAmB,EAAE,MAAM;KAC5B,CAAC,CAAA;IAEF,MAAM,OAAO,GAAG,GAAG,WAAW,CAAC,OAAO,cAAc,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAA;IAEvE,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,SAAwB,yBAAyB,CAAC,GAAY,EAAE,GAAa;IAC3E,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,wBAAwB,EAAE,CAAA;QAE1C,GAAG,CAAC,IAAI,CAAC;YACP,IAAI,EAAE,IAAI;YACV,IAAI,EAAE;gBACJ,OAAO;aACR;SACF,CAAC,CAAA;IACJ,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;YACnB,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,KAAK,CAAC,OAAO;SACvB,CAAC,CAAA;IACJ,CAAC;AACH,CAAC"}
|