@windrun-huaiin/backend-core 14.3.0 → 14.5.0
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/app/api/stripe/checkout/route.js +1 -1
- package/dist/app/api/stripe/checkout/route.mjs +1 -1
- package/dist/app/api/stripe/customer-portal/route.js +1 -1
- package/dist/app/api/stripe/customer-portal/route.mjs +1 -1
- package/dist/app/api/user/anonymous/init/route.d.ts.map +1 -1
- package/dist/app/api/user/anonymous/init/route.js +8 -6
- package/dist/app/api/user/anonymous/init/route.mjs +4 -2
- package/dist/auth/auth-middleware.d.ts +13 -0
- package/dist/auth/auth-middleware.d.ts.map +1 -0
- package/dist/auth/auth-middleware.js +86 -0
- package/dist/auth/auth-middleware.mjs +82 -0
- package/dist/auth/auth-shared.d.ts +14 -0
- package/dist/auth/auth-shared.d.ts.map +1 -0
- package/dist/auth/auth-shared.js +13 -0
- package/dist/auth/auth-shared.mjs +10 -0
- package/dist/auth/auth-utils.d.ts +58 -0
- package/dist/auth/auth-utils.d.ts.map +1 -0
- package/dist/auth/auth-utils.js +163 -0
- package/dist/auth/auth-utils.mjs +156 -0
- package/dist/index.js +0 -5
- package/dist/index.mjs +0 -1
- package/dist/lib/index.d.ts +0 -1
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +0 -5
- package/dist/lib/index.mjs +0 -1
- package/dist/lib/money-price-helper.d.ts.map +1 -1
- package/dist/lib/money-price-helper.js +6 -4
- package/dist/lib/money-price-helper.mjs +4 -2
- package/package.json +18 -3
- package/src/app/api/stripe/checkout/route.ts +1 -1
- package/src/app/api/stripe/customer-portal/route.ts +1 -1
- package/src/app/api/user/anonymous/init/route.ts +3 -2
- package/src/auth/auth-middleware.ts +109 -0
- package/src/auth/auth-shared.ts +16 -0
- package/src/{lib → auth}/auth-utils.ts +64 -10
- package/src/lib/index.ts +0 -1
- package/src/lib/money-price-helper.ts +3 -2
|
@@ -9,7 +9,7 @@ require('../../../../prisma/prisma.js');
|
|
|
9
9
|
require('../../../../services/database/credit.service.js');
|
|
10
10
|
var transaction_service = require('../../../../services/database/transaction.service.js');
|
|
11
11
|
require('@prisma/client');
|
|
12
|
-
var authUtils = require('../../../../
|
|
12
|
+
var authUtils = require('../../../../auth/auth-utils.js');
|
|
13
13
|
var moneyPriceConfig = require('../../../../lib/money-price-config.js');
|
|
14
14
|
|
|
15
15
|
// Request validation schema
|
|
@@ -7,7 +7,7 @@ import '../../../../prisma/prisma.mjs';
|
|
|
7
7
|
import '../../../../services/database/credit.service.mjs';
|
|
8
8
|
import { transactionService } from '../../../../services/database/transaction.service.mjs';
|
|
9
9
|
import '@prisma/client';
|
|
10
|
-
import { ApiAuthUtils } from '../../../../
|
|
10
|
+
import { ApiAuthUtils } from '../../../../auth/auth-utils.mjs';
|
|
11
11
|
import { getPriceConfig } from '../../../../lib/money-price-config.mjs';
|
|
12
12
|
|
|
13
13
|
// Request validation schema
|
|
@@ -4,7 +4,7 @@ var tslib_es6 = require('../../../../node_modules/.pnpm/@rollup_plugin-typescrip
|
|
|
4
4
|
var server = require('next/server');
|
|
5
5
|
var zod = require('zod');
|
|
6
6
|
var stripeConfig = require('../../../../lib/stripe-config.js');
|
|
7
|
-
var authUtils = require('../../../../
|
|
7
|
+
var authUtils = require('../../../../auth/auth-utils.js');
|
|
8
8
|
require('../../../../prisma/prisma.js');
|
|
9
9
|
var subscription_service = require('../../../../services/database/subscription.service.js');
|
|
10
10
|
require('../../../../services/database/credit.service.js');
|
|
@@ -2,7 +2,7 @@ import { __awaiter } from '../../../../node_modules/.pnpm/@rollup_plugin-typescr
|
|
|
2
2
|
import { NextResponse } from 'next/server';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { createOrGetCustomer, createCustomerPortalSession } from '../../../../lib/stripe-config.mjs';
|
|
5
|
-
import { ApiAuthUtils } from '../../../../
|
|
5
|
+
import { ApiAuthUtils } from '../../../../auth/auth-utils.mjs';
|
|
6
6
|
import '../../../../prisma/prisma.mjs';
|
|
7
7
|
import { subscriptionService } from '../../../../services/database/subscription.service.mjs';
|
|
8
8
|
import '../../../../services/database/credit.service.mjs';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../src/app/api/user/anonymous/init/route.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../src/app/api/user/anonymous/init/route.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA6rBxD;;;GAGG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,kCAE9C"}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
var tslib_es6 = require('../../../../../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.js');
|
|
4
4
|
var anonymous_aggregate_service = require('../../../../../services/aggregate/anonymous.aggregate.service.js');
|
|
5
|
+
var authUtils = require('../../../../../auth/auth-utils.js');
|
|
5
6
|
var server = require('@windrun-huaiin/third-ui/fingerprint/server');
|
|
6
|
-
var server$1 = require('
|
|
7
|
-
var server$2 = require('next/server');
|
|
7
|
+
var server$1 = require('next/server');
|
|
8
8
|
var userContextService = require('../../../../../services/context/user-context-service.js');
|
|
9
9
|
var userContextFinalizer = require('../../../../../services/context/user-context-finalizer.js');
|
|
10
10
|
|
|
@@ -22,7 +22,7 @@ function createSuccessResponse(params) {
|
|
|
22
22
|
/** 创建错误响应 */
|
|
23
23
|
function createErrorResponse(message, status = 400) {
|
|
24
24
|
const errorResponse = { error: message };
|
|
25
|
-
return server$
|
|
25
|
+
return server$1.NextResponse.json(errorResponse, { status });
|
|
26
26
|
}
|
|
27
27
|
const SOURCE_REF_MAX_LENGTH = 2048;
|
|
28
28
|
const QUERY_PARAM_MAX_LENGTH = 512;
|
|
@@ -494,6 +494,7 @@ function getUserByFingerprintId(fingerprintId) {
|
|
|
494
494
|
*/
|
|
495
495
|
function handleFingerprintRequest(request_1) {
|
|
496
496
|
return tslib_es6.__awaiter(this, arguments, void 0, function* (request, options = {}) {
|
|
497
|
+
var _a;
|
|
497
498
|
// 从请求中提取fingerprint ID
|
|
498
499
|
const fingerprintId = server.extractFingerprintFromNextRequest(request);
|
|
499
500
|
// 验证fingerprint ID
|
|
@@ -501,7 +502,8 @@ function handleFingerprintRequest(request_1) {
|
|
|
501
502
|
return createErrorResponse('Invalid or missing fingerprint ID');
|
|
502
503
|
}
|
|
503
504
|
console.log('Received fingerprintId:', fingerprintId);
|
|
504
|
-
const
|
|
505
|
+
const authIdentity = yield authUtils.getOptionalServerAuthIdentity();
|
|
506
|
+
const clerkUserId = (_a = authIdentity === null || authIdentity === void 0 ? void 0 : authIdentity.providerUserId) !== null && _a !== void 0 ? _a : null;
|
|
505
507
|
try {
|
|
506
508
|
// 优先根据 Clerk ID 查询(如果已登录)
|
|
507
509
|
let existingUserResult = null;
|
|
@@ -521,7 +523,7 @@ function handleFingerprintRequest(request_1) {
|
|
|
521
523
|
existingUserResult = yield getUserByFingerprintId(fingerprintId);
|
|
522
524
|
}
|
|
523
525
|
if (existingUserResult) {
|
|
524
|
-
return server$
|
|
526
|
+
return server$1.NextResponse.json(existingUserResult);
|
|
525
527
|
}
|
|
526
528
|
// 如果不存在用户且不允许创建,返回404
|
|
527
529
|
if (!options.createIfNotExists) {
|
|
@@ -545,7 +547,7 @@ function handleFingerprintRequest(request_1) {
|
|
|
545
547
|
hasAnonymousUser: anonymousInitResult.hasAnonymousUser,
|
|
546
548
|
},
|
|
547
549
|
});
|
|
548
|
-
return server$
|
|
550
|
+
return server$1.NextResponse.json(response);
|
|
549
551
|
}
|
|
550
552
|
catch (error) {
|
|
551
553
|
console.error('Fingerprint request error:', error);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __awaiter, __rest } from '../../../../../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.mjs';
|
|
2
2
|
import { anonymousAggregateService } from '../../../../../services/aggregate/anonymous.aggregate.service.mjs';
|
|
3
|
+
import { getOptionalServerAuthIdentity } from '../../../../../auth/auth-utils.mjs';
|
|
3
4
|
import { extractFingerprintFromNextRequest } from '@windrun-huaiin/third-ui/fingerprint/server';
|
|
4
|
-
import { auth } from '@clerk/nextjs/server';
|
|
5
5
|
import { NextResponse } from 'next/server';
|
|
6
6
|
import { fetchUserContextByClerkUserId, fetchLatestUserContextByFingerprintId, mapSubscriptionToXSubscription, mapCreditToXCredit, mapUserToXUser } from '../../../../../services/context/user-context-service.mjs';
|
|
7
7
|
import { finalizeUserContext } from '../../../../../services/context/user-context-finalizer.mjs';
|
|
@@ -492,6 +492,7 @@ function getUserByFingerprintId(fingerprintId) {
|
|
|
492
492
|
*/
|
|
493
493
|
function handleFingerprintRequest(request_1) {
|
|
494
494
|
return __awaiter(this, arguments, void 0, function* (request, options = {}) {
|
|
495
|
+
var _a;
|
|
495
496
|
// 从请求中提取fingerprint ID
|
|
496
497
|
const fingerprintId = extractFingerprintFromNextRequest(request);
|
|
497
498
|
// 验证fingerprint ID
|
|
@@ -499,7 +500,8 @@ function handleFingerprintRequest(request_1) {
|
|
|
499
500
|
return createErrorResponse('Invalid or missing fingerprint ID');
|
|
500
501
|
}
|
|
501
502
|
console.log('Received fingerprintId:', fingerprintId);
|
|
502
|
-
const
|
|
503
|
+
const authIdentity = yield getOptionalServerAuthIdentity();
|
|
504
|
+
const clerkUserId = (_a = authIdentity === null || authIdentity === void 0 ? void 0 : authIdentity.providerUserId) !== null && _a !== void 0 ? _a : null;
|
|
503
505
|
try {
|
|
504
506
|
// 优先根据 Clerk ID 查询(如果已登录)
|
|
505
507
|
let existingUserResult = null;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ClerkMiddlewareAuth } from '@clerk/nextjs/server';
|
|
2
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
3
|
+
import { type ProviderIdentity } from './auth-shared';
|
|
4
|
+
export declare function buildProtectedPageRoutePatterns(protectedRoots: readonly string[], locales: readonly string[]): string[];
|
|
5
|
+
export interface AuthMiddlewareOptions {
|
|
6
|
+
protectedPageRoutes: (req: NextRequest) => boolean;
|
|
7
|
+
protectedApiRoutes: (req: NextRequest) => boolean;
|
|
8
|
+
publicApiRoutes: (req: NextRequest) => boolean;
|
|
9
|
+
intlMiddleware: (req: NextRequest) => ReturnType<typeof NextResponse.next> | Response | undefined;
|
|
10
|
+
}
|
|
11
|
+
export declare function buildAuthenticatedRequestHeaders(req: NextRequest, auth: ProviderIdentity): Headers;
|
|
12
|
+
export declare function handleAuthMiddleware(auth: ClerkMiddlewareAuth, req: NextRequest, options: AuthMiddlewareOptions): Promise<Response | null | undefined>;
|
|
13
|
+
//# sourceMappingURL=auth-middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-middleware.d.ts","sourceRoot":"","sources":["../../src/auth/auth-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEpE,wBAAgB,+BAA+B,CAC7C,cAAc,EAAE,SAAS,MAAM,EAAE,EACjC,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,MAAM,EAAE,CAsBV;AAED,MAAM,WAAW,qBAAqB;IACpC,mBAAmB,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC;IACnD,kBAAkB,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC;IAClD,eAAe,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC;IAC/C,cAAc,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,UAAU,CAAC,OAAO,YAAY,CAAC,IAAI,CAAC,GAAG,QAAQ,GAAG,SAAS,CAAC;CACnG;AAcD,wBAAgB,gCAAgC,CAC9C,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAKT;AAED,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,mBAAmB,EACzB,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,qBAAqB,wCA6C/B"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var tslib_es6 = require('../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.js');
|
|
4
|
+
var server = require('next/server');
|
|
5
|
+
var authShared = require('./auth-shared.js');
|
|
6
|
+
|
|
7
|
+
function buildProtectedPageRoutePatterns(protectedRoots, locales) {
|
|
8
|
+
const uniqueRoots = [...new Set(protectedRoots)]
|
|
9
|
+
.map((root) => root.trim())
|
|
10
|
+
.filter(Boolean)
|
|
11
|
+
.map((root) => (root.startsWith('/') ? root : `/${root}`))
|
|
12
|
+
.map((root) => root.replace(/\/+$/, ''));
|
|
13
|
+
const uniqueLocales = [...new Set(locales)]
|
|
14
|
+
.map((locale) => locale.trim())
|
|
15
|
+
.filter(Boolean);
|
|
16
|
+
const patterns = new Set();
|
|
17
|
+
for (const root of uniqueRoots) {
|
|
18
|
+
patterns.add(`${root}(.*)`);
|
|
19
|
+
for (const locale of uniqueLocales) {
|
|
20
|
+
patterns.add(`/${locale}${root}(.*)`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return [...patterns];
|
|
24
|
+
}
|
|
25
|
+
function authenticateWithClerk(auth) {
|
|
26
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
27
|
+
const { userId } = yield auth();
|
|
28
|
+
if (!userId) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
provider: 'clerk',
|
|
33
|
+
providerUserId: userId,
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function buildAuthenticatedRequestHeaders(req, auth) {
|
|
38
|
+
const headers = new Headers(req.headers);
|
|
39
|
+
headers.set(authShared.AUTH_HEADERS.provider, auth.provider);
|
|
40
|
+
headers.set(authShared.AUTH_HEADERS.providerUserId, auth.providerUserId);
|
|
41
|
+
return headers;
|
|
42
|
+
}
|
|
43
|
+
function handleAuthMiddleware(auth, req, options) {
|
|
44
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
45
|
+
const { protectedPageRoutes, protectedApiRoutes, publicApiRoutes, intlMiddleware } = options;
|
|
46
|
+
if (protectedPageRoutes(req)) {
|
|
47
|
+
const identity = yield authenticateWithClerk(auth);
|
|
48
|
+
if (!identity) {
|
|
49
|
+
return (yield auth()).redirectToSignIn();
|
|
50
|
+
}
|
|
51
|
+
const requestHeaders = buildAuthenticatedRequestHeaders(req, identity);
|
|
52
|
+
console.log('Forward auth context for protected page:', identity.provider, identity.providerUserId);
|
|
53
|
+
return intlMiddleware(new server.NextRequest(req.url, {
|
|
54
|
+
headers: requestHeaders,
|
|
55
|
+
method: req.method,
|
|
56
|
+
body: req.body,
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
if (protectedApiRoutes(req)) {
|
|
60
|
+
const identity = yield authenticateWithClerk(auth);
|
|
61
|
+
if (!identity) {
|
|
62
|
+
return (yield auth()).redirectToSignIn();
|
|
63
|
+
}
|
|
64
|
+
const requestHeaders = buildAuthenticatedRequestHeaders(req, identity);
|
|
65
|
+
console.log('Forward auth context for protected API:', identity.provider, identity.providerUserId);
|
|
66
|
+
return server.NextResponse.next({
|
|
67
|
+
request: {
|
|
68
|
+
headers: requestHeaders,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
if (publicApiRoutes(req)) {
|
|
73
|
+
console.log('Public API route, no auth required:', req.nextUrl.pathname);
|
|
74
|
+
return server.NextResponse.next();
|
|
75
|
+
}
|
|
76
|
+
if (req.nextUrl.pathname.startsWith('/api/')) {
|
|
77
|
+
console.log('Other API route, no internationalization:', req.nextUrl.pathname);
|
|
78
|
+
return server.NextResponse.next();
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
exports.buildAuthenticatedRequestHeaders = buildAuthenticatedRequestHeaders;
|
|
85
|
+
exports.buildProtectedPageRoutePatterns = buildProtectedPageRoutePatterns;
|
|
86
|
+
exports.handleAuthMiddleware = handleAuthMiddleware;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { __awaiter } from '../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.mjs';
|
|
2
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
3
|
+
import { AUTH_HEADERS } from './auth-shared.mjs';
|
|
4
|
+
|
|
5
|
+
function buildProtectedPageRoutePatterns(protectedRoots, locales) {
|
|
6
|
+
const uniqueRoots = [...new Set(protectedRoots)]
|
|
7
|
+
.map((root) => root.trim())
|
|
8
|
+
.filter(Boolean)
|
|
9
|
+
.map((root) => (root.startsWith('/') ? root : `/${root}`))
|
|
10
|
+
.map((root) => root.replace(/\/+$/, ''));
|
|
11
|
+
const uniqueLocales = [...new Set(locales)]
|
|
12
|
+
.map((locale) => locale.trim())
|
|
13
|
+
.filter(Boolean);
|
|
14
|
+
const patterns = new Set();
|
|
15
|
+
for (const root of uniqueRoots) {
|
|
16
|
+
patterns.add(`${root}(.*)`);
|
|
17
|
+
for (const locale of uniqueLocales) {
|
|
18
|
+
patterns.add(`/${locale}${root}(.*)`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return [...patterns];
|
|
22
|
+
}
|
|
23
|
+
function authenticateWithClerk(auth) {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
const { userId } = yield auth();
|
|
26
|
+
if (!userId) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
provider: 'clerk',
|
|
31
|
+
providerUserId: userId,
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function buildAuthenticatedRequestHeaders(req, auth) {
|
|
36
|
+
const headers = new Headers(req.headers);
|
|
37
|
+
headers.set(AUTH_HEADERS.provider, auth.provider);
|
|
38
|
+
headers.set(AUTH_HEADERS.providerUserId, auth.providerUserId);
|
|
39
|
+
return headers;
|
|
40
|
+
}
|
|
41
|
+
function handleAuthMiddleware(auth, req, options) {
|
|
42
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
43
|
+
const { protectedPageRoutes, protectedApiRoutes, publicApiRoutes, intlMiddleware } = options;
|
|
44
|
+
if (protectedPageRoutes(req)) {
|
|
45
|
+
const identity = yield authenticateWithClerk(auth);
|
|
46
|
+
if (!identity) {
|
|
47
|
+
return (yield auth()).redirectToSignIn();
|
|
48
|
+
}
|
|
49
|
+
const requestHeaders = buildAuthenticatedRequestHeaders(req, identity);
|
|
50
|
+
console.log('Forward auth context for protected page:', identity.provider, identity.providerUserId);
|
|
51
|
+
return intlMiddleware(new NextRequest(req.url, {
|
|
52
|
+
headers: requestHeaders,
|
|
53
|
+
method: req.method,
|
|
54
|
+
body: req.body,
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
if (protectedApiRoutes(req)) {
|
|
58
|
+
const identity = yield authenticateWithClerk(auth);
|
|
59
|
+
if (!identity) {
|
|
60
|
+
return (yield auth()).redirectToSignIn();
|
|
61
|
+
}
|
|
62
|
+
const requestHeaders = buildAuthenticatedRequestHeaders(req, identity);
|
|
63
|
+
console.log('Forward auth context for protected API:', identity.provider, identity.providerUserId);
|
|
64
|
+
return NextResponse.next({
|
|
65
|
+
request: {
|
|
66
|
+
headers: requestHeaders,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
if (publicApiRoutes(req)) {
|
|
71
|
+
console.log('Public API route, no auth required:', req.nextUrl.pathname);
|
|
72
|
+
return NextResponse.next();
|
|
73
|
+
}
|
|
74
|
+
if (req.nextUrl.pathname.startsWith('/api/')) {
|
|
75
|
+
console.log('Other API route, no internationalization:', req.nextUrl.pathname);
|
|
76
|
+
return NextResponse.next();
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export { buildAuthenticatedRequestHeaders, buildProtectedPageRoutePatterns, handleAuthMiddleware };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const AUTH_HEADERS: {
|
|
2
|
+
readonly provider: "x-auth-provider";
|
|
3
|
+
readonly providerUserId: "x-auth-provider-user-id";
|
|
4
|
+
};
|
|
5
|
+
export declare const AUTH_ERRORS: {
|
|
6
|
+
readonly unauthorized: "UNAUTHORIZED";
|
|
7
|
+
readonly userNotFound: "USER_NOT_FOUND";
|
|
8
|
+
};
|
|
9
|
+
export type AuthProvider = 'clerk';
|
|
10
|
+
export interface ProviderIdentity {
|
|
11
|
+
provider: AuthProvider;
|
|
12
|
+
providerUserId: string;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=auth-shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-shared.d.ts","sourceRoot":"","sources":["../../src/auth/auth-shared.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAEX,eAAO,MAAM,WAAW;;;CAGd,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC;AAEnC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,YAAY,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const AUTH_HEADERS = {
|
|
4
|
+
provider: 'x-auth-provider',
|
|
5
|
+
providerUserId: 'x-auth-provider-user-id',
|
|
6
|
+
};
|
|
7
|
+
const AUTH_ERRORS = {
|
|
8
|
+
unauthorized: 'UNAUTHORIZED',
|
|
9
|
+
userNotFound: 'USER_NOT_FOUND',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
exports.AUTH_ERRORS = AUTH_ERRORS;
|
|
13
|
+
exports.AUTH_HEADERS = AUTH_HEADERS;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { NextRequest } from 'next/server';
|
|
2
|
+
import { User } from '../services/database/prisma-model-type';
|
|
3
|
+
import { type AuthProvider, type ProviderIdentity } from './auth-shared';
|
|
4
|
+
/**
|
|
5
|
+
* 认证结果类型
|
|
6
|
+
*/
|
|
7
|
+
export interface AuthResult {
|
|
8
|
+
userId: string;
|
|
9
|
+
user: User;
|
|
10
|
+
provider: AuthProvider;
|
|
11
|
+
providerUserId: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 从中间件设置的 Clerk ID 获取完整用户信息
|
|
15
|
+
*/
|
|
16
|
+
export declare function getAuthenticatedUser(req: NextRequest): Promise<AuthResult>;
|
|
17
|
+
/**
|
|
18
|
+
* 要求用户必须已认证,返回用户ID
|
|
19
|
+
*/
|
|
20
|
+
export declare function requireAuth(req: NextRequest): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
* 要求用户必须已认证,返回完整用户信息
|
|
23
|
+
*/
|
|
24
|
+
export declare function requireAuthWithUser(req: NextRequest): Promise<AuthResult>;
|
|
25
|
+
/**
|
|
26
|
+
* 服务端场景下获取当前已认证身份(如果存在)
|
|
27
|
+
* 适用于只依赖登录态、不需要查询业务用户的逻辑
|
|
28
|
+
*/
|
|
29
|
+
export declare function getOptionalServerAuthIdentity(): Promise<ProviderIdentity | null>;
|
|
30
|
+
/**
|
|
31
|
+
* 服务端场景下获取当前已认证用户(如果存在)
|
|
32
|
+
* 适用于 Server Component / Server Action 中基于登录态控制展示的逻辑
|
|
33
|
+
*/
|
|
34
|
+
export declare function getOptionalServerAuthUser(): Promise<AuthResult | null>;
|
|
35
|
+
/**
|
|
36
|
+
* API Route版本的认证工具函数
|
|
37
|
+
*/
|
|
38
|
+
export declare class ApiAuthUtils {
|
|
39
|
+
private req;
|
|
40
|
+
constructor(req: NextRequest);
|
|
41
|
+
/**
|
|
42
|
+
* 要求用户必须已认证,返回用户ID
|
|
43
|
+
*/
|
|
44
|
+
requireAuth(): Promise<string>;
|
|
45
|
+
/**
|
|
46
|
+
* 要求用户必须已认证,返回完整用户信息
|
|
47
|
+
*/
|
|
48
|
+
requireAuthWithUser(): Promise<AuthResult>;
|
|
49
|
+
/**
|
|
50
|
+
* 获取用户ID(如果已认证)
|
|
51
|
+
*/
|
|
52
|
+
getUserId(): Promise<string | null>;
|
|
53
|
+
/**
|
|
54
|
+
* 获取完整用户信息(如果已认证)
|
|
55
|
+
*/
|
|
56
|
+
getUser(): Promise<AuthResult | null>;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=auth-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-utils.d.ts","sourceRoot":"","sources":["../../src/auth/auth-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1C,OAAO,EAAE,IAAI,EAAE,MAAM,wCAAwC,CAAC;AAC9D,OAAO,EAA6B,KAAK,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEpG;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,IAAI,CAAC;IACX,QAAQ,EAAE,YAAY,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAuBhF;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAGnE;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAE/E;AAED;;;GAGG;AACH,wBAAsB,6BAA6B,IAAI,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAetF;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAsB5E;AAED;;GAEG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,GAAG,CAAc;gBAEb,GAAG,EAAE,WAAW;IAI5B;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;IAIpC;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,UAAU,CAAC;IAIhD;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IASzC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;CAO5C"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var tslib_es6 = require('../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.js');
|
|
4
|
+
var server = require('@clerk/nextjs/server');
|
|
5
|
+
var user_service = require('../services/database/user.service.js');
|
|
6
|
+
require('../prisma/prisma.js');
|
|
7
|
+
require('../services/database/credit.service.js');
|
|
8
|
+
require('@prisma/client');
|
|
9
|
+
var authShared = require('./auth-shared.js');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 从中间件设置的 Clerk ID 获取完整用户信息
|
|
13
|
+
*/
|
|
14
|
+
function getAuthenticatedUser(req) {
|
|
15
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
16
|
+
try {
|
|
17
|
+
const provider = req.headers.get(authShared.AUTH_HEADERS.provider);
|
|
18
|
+
const providerUserId = req.headers.get(authShared.AUTH_HEADERS.providerUserId);
|
|
19
|
+
if (provider !== 'clerk' || !providerUserId) {
|
|
20
|
+
throw new Error(authShared.AUTH_ERRORS.unauthorized);
|
|
21
|
+
}
|
|
22
|
+
const user = yield user_service.userService.findByClerkUserId(providerUserId);
|
|
23
|
+
if (!user) {
|
|
24
|
+
throw new Error(authShared.AUTH_ERRORS.userNotFound);
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
userId: user.userId,
|
|
28
|
+
user,
|
|
29
|
+
provider: 'clerk',
|
|
30
|
+
providerUserId,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
console.error('Error getting authenticated user:', error);
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 要求用户必须已认证,返回用户ID
|
|
41
|
+
*/
|
|
42
|
+
function requireAuth(req) {
|
|
43
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
44
|
+
const auth = yield getAuthenticatedUser(req);
|
|
45
|
+
return auth.userId;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 要求用户必须已认证,返回完整用户信息
|
|
50
|
+
*/
|
|
51
|
+
function requireAuthWithUser(req) {
|
|
52
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
53
|
+
return yield getAuthenticatedUser(req);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 服务端场景下获取当前已认证身份(如果存在)
|
|
58
|
+
* 适用于只依赖登录态、不需要查询业务用户的逻辑
|
|
59
|
+
*/
|
|
60
|
+
function getOptionalServerAuthIdentity() {
|
|
61
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
62
|
+
try {
|
|
63
|
+
const { userId: providerUserId } = yield server.auth();
|
|
64
|
+
if (!providerUserId) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
provider: 'clerk',
|
|
69
|
+
providerUserId,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
console.error('Error getting optional server auth identity:', error);
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 服务端场景下获取当前已认证用户(如果存在)
|
|
80
|
+
* 适用于 Server Component / Server Action 中基于登录态控制展示的逻辑
|
|
81
|
+
*/
|
|
82
|
+
function getOptionalServerAuthUser() {
|
|
83
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
84
|
+
try {
|
|
85
|
+
const identity = yield getOptionalServerAuthIdentity();
|
|
86
|
+
if (!identity) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const user = yield user_service.userService.findByClerkUserId(identity.providerUserId);
|
|
90
|
+
if (!user) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
userId: user.userId,
|
|
95
|
+
user,
|
|
96
|
+
provider: identity.provider,
|
|
97
|
+
providerUserId: identity.providerUserId,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
console.error('Error getting optional server auth user:', error);
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* API Route版本的认证工具函数
|
|
108
|
+
*/
|
|
109
|
+
class ApiAuthUtils {
|
|
110
|
+
constructor(req) {
|
|
111
|
+
this.req = req;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 要求用户必须已认证,返回用户ID
|
|
115
|
+
*/
|
|
116
|
+
requireAuth() {
|
|
117
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
118
|
+
return yield requireAuth(this.req);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* 要求用户必须已认证,返回完整用户信息
|
|
123
|
+
*/
|
|
124
|
+
requireAuthWithUser() {
|
|
125
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
126
|
+
return yield requireAuthWithUser(this.req);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* 获取用户ID(如果已认证)
|
|
131
|
+
*/
|
|
132
|
+
getUserId() {
|
|
133
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
134
|
+
try {
|
|
135
|
+
const auth = yield getAuthenticatedUser(this.req);
|
|
136
|
+
return auth.userId;
|
|
137
|
+
}
|
|
138
|
+
catch (_a) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* 获取完整用户信息(如果已认证)
|
|
145
|
+
*/
|
|
146
|
+
getUser() {
|
|
147
|
+
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
148
|
+
try {
|
|
149
|
+
return yield getAuthenticatedUser(this.req);
|
|
150
|
+
}
|
|
151
|
+
catch (_a) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
exports.ApiAuthUtils = ApiAuthUtils;
|
|
159
|
+
exports.getAuthenticatedUser = getAuthenticatedUser;
|
|
160
|
+
exports.getOptionalServerAuthIdentity = getOptionalServerAuthIdentity;
|
|
161
|
+
exports.getOptionalServerAuthUser = getOptionalServerAuthUser;
|
|
162
|
+
exports.requireAuth = requireAuth;
|
|
163
|
+
exports.requireAuthWithUser = requireAuthWithUser;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { __awaiter } from '../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.mjs';
|
|
2
|
+
import { auth } from '@clerk/nextjs/server';
|
|
3
|
+
import { userService } from '../services/database/user.service.mjs';
|
|
4
|
+
import '../prisma/prisma.mjs';
|
|
5
|
+
import '../services/database/credit.service.mjs';
|
|
6
|
+
import '@prisma/client';
|
|
7
|
+
import { AUTH_HEADERS, AUTH_ERRORS } from './auth-shared.mjs';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 从中间件设置的 Clerk ID 获取完整用户信息
|
|
11
|
+
*/
|
|
12
|
+
function getAuthenticatedUser(req) {
|
|
13
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
14
|
+
try {
|
|
15
|
+
const provider = req.headers.get(AUTH_HEADERS.provider);
|
|
16
|
+
const providerUserId = req.headers.get(AUTH_HEADERS.providerUserId);
|
|
17
|
+
if (provider !== 'clerk' || !providerUserId) {
|
|
18
|
+
throw new Error(AUTH_ERRORS.unauthorized);
|
|
19
|
+
}
|
|
20
|
+
const user = yield userService.findByClerkUserId(providerUserId);
|
|
21
|
+
if (!user) {
|
|
22
|
+
throw new Error(AUTH_ERRORS.userNotFound);
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
userId: user.userId,
|
|
26
|
+
user,
|
|
27
|
+
provider: 'clerk',
|
|
28
|
+
providerUserId,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.error('Error getting authenticated user:', error);
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* 要求用户必须已认证,返回用户ID
|
|
39
|
+
*/
|
|
40
|
+
function requireAuth(req) {
|
|
41
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
42
|
+
const auth = yield getAuthenticatedUser(req);
|
|
43
|
+
return auth.userId;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 要求用户必须已认证,返回完整用户信息
|
|
48
|
+
*/
|
|
49
|
+
function requireAuthWithUser(req) {
|
|
50
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
return yield getAuthenticatedUser(req);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 服务端场景下获取当前已认证身份(如果存在)
|
|
56
|
+
* 适用于只依赖登录态、不需要查询业务用户的逻辑
|
|
57
|
+
*/
|
|
58
|
+
function getOptionalServerAuthIdentity() {
|
|
59
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
60
|
+
try {
|
|
61
|
+
const { userId: providerUserId } = yield auth();
|
|
62
|
+
if (!providerUserId) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
provider: 'clerk',
|
|
67
|
+
providerUserId,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
console.error('Error getting optional server auth identity:', error);
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* 服务端场景下获取当前已认证用户(如果存在)
|
|
78
|
+
* 适用于 Server Component / Server Action 中基于登录态控制展示的逻辑
|
|
79
|
+
*/
|
|
80
|
+
function getOptionalServerAuthUser() {
|
|
81
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
82
|
+
try {
|
|
83
|
+
const identity = yield getOptionalServerAuthIdentity();
|
|
84
|
+
if (!identity) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
const user = yield userService.findByClerkUserId(identity.providerUserId);
|
|
88
|
+
if (!user) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
userId: user.userId,
|
|
93
|
+
user,
|
|
94
|
+
provider: identity.provider,
|
|
95
|
+
providerUserId: identity.providerUserId,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
console.error('Error getting optional server auth user:', error);
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* API Route版本的认证工具函数
|
|
106
|
+
*/
|
|
107
|
+
class ApiAuthUtils {
|
|
108
|
+
constructor(req) {
|
|
109
|
+
this.req = req;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 要求用户必须已认证,返回用户ID
|
|
113
|
+
*/
|
|
114
|
+
requireAuth() {
|
|
115
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
116
|
+
return yield requireAuth(this.req);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 要求用户必须已认证,返回完整用户信息
|
|
121
|
+
*/
|
|
122
|
+
requireAuthWithUser() {
|
|
123
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
124
|
+
return yield requireAuthWithUser(this.req);
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* 获取用户ID(如果已认证)
|
|
129
|
+
*/
|
|
130
|
+
getUserId() {
|
|
131
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
132
|
+
try {
|
|
133
|
+
const auth = yield getAuthenticatedUser(this.req);
|
|
134
|
+
return auth.userId;
|
|
135
|
+
}
|
|
136
|
+
catch (_a) {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* 获取完整用户信息(如果已认证)
|
|
143
|
+
*/
|
|
144
|
+
getUser() {
|
|
145
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
146
|
+
try {
|
|
147
|
+
return yield getAuthenticatedUser(this.req);
|
|
148
|
+
}
|
|
149
|
+
catch (_a) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export { ApiAuthUtils, getAuthenticatedUser, getOptionalServerAuthIdentity, getOptionalServerAuthUser, requireAuth, requireAuthWithUser };
|
package/dist/index.js
CHANGED
|
@@ -21,7 +21,6 @@ var moneyPriceHelper = require('./lib/money-price-helper.js');
|
|
|
21
21
|
var fingerprintConfig = require('./lib/fingerprint-config.js');
|
|
22
22
|
var creditInit = require('./lib/credit-init.js');
|
|
23
23
|
var stripeConfig = require('./lib/stripe-config.js');
|
|
24
|
-
var authUtils = require('./lib/auth-utils.js');
|
|
25
24
|
var upstashConfig = require('./lib/upstash-config.js');
|
|
26
25
|
var redisLock = require('./lib/upstash/redis-lock.js');
|
|
27
26
|
var redisLike = require('./lib/upstash/redis-like.js');
|
|
@@ -91,10 +90,6 @@ exports.fetchPaymentId = stripeConfig.fetchPaymentId;
|
|
|
91
90
|
exports.getStripe = stripeConfig.getStripe;
|
|
92
91
|
exports.updateSubscription = stripeConfig.updateSubscription;
|
|
93
92
|
exports.validateStripeWebhook = stripeConfig.validateStripeWebhook;
|
|
94
|
-
exports.ApiAuthUtils = authUtils.ApiAuthUtils;
|
|
95
|
-
exports.getAuthenticatedUser = authUtils.getAuthenticatedUser;
|
|
96
|
-
exports.requireAuth = authUtils.requireAuth;
|
|
97
|
-
exports.requireAuthWithUser = authUtils.requireAuthWithUser;
|
|
98
93
|
exports.getQstash = upstashConfig.getQstash;
|
|
99
94
|
exports.getRedis = upstashConfig.getRedis;
|
|
100
95
|
exports.withQstash = upstashConfig.withQstash;
|
package/dist/index.mjs
CHANGED
|
@@ -19,7 +19,6 @@ export { getMoneyPriceInitUserContext } from './lib/money-price-helper.mjs';
|
|
|
19
19
|
export { fingerprintConfig } from './lib/fingerprint-config.mjs';
|
|
20
20
|
export { creditsConfig, freeAmount, freeExpiredDays, freeRegisterAmount, oneTimeExpiredDays } from './lib/credit-init.mjs';
|
|
21
21
|
export { ActiveSubscriptionExistsError, cancelSubscription, createCheckoutSession, createCustomerPortalSession, createOrGetCustomer, fetchPaymentId, getStripe, updateSubscription, validateStripeWebhook } from './lib/stripe-config.mjs';
|
|
22
|
-
export { ApiAuthUtils, getAuthenticatedUser, requireAuth, requireAuthWithUser } from './lib/auth-utils.mjs';
|
|
23
22
|
export { getQstash, getRedis, withQstash, withRedis } from './lib/upstash-config.mjs';
|
|
24
23
|
export { acquireLock, releaseLock, withLock } from './lib/upstash/redis-lock.mjs';
|
|
25
24
|
export { getTargetLikeCount, getUserLikedTargets, isTargetLiked, likeTarget, unlikeTarget } from './lib/upstash/redis-like.mjs';
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -3,7 +3,6 @@ export * from './money-price-helper';
|
|
|
3
3
|
export * from './fingerprint-config';
|
|
4
4
|
export * from './credit-init';
|
|
5
5
|
export * from './stripe-config';
|
|
6
|
-
export * from './auth-utils';
|
|
7
6
|
export * from './upstash-config';
|
|
8
7
|
export * from './upstash';
|
|
9
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC"}
|
package/dist/lib/index.js
CHANGED
|
@@ -5,7 +5,6 @@ var moneyPriceHelper = require('./money-price-helper.js');
|
|
|
5
5
|
var fingerprintConfig = require('./fingerprint-config.js');
|
|
6
6
|
var creditInit = require('./credit-init.js');
|
|
7
7
|
var stripeConfig = require('./stripe-config.js');
|
|
8
|
-
var authUtils = require('./auth-utils.js');
|
|
9
8
|
var upstashConfig = require('./upstash-config.js');
|
|
10
9
|
var redisLock = require('./upstash/redis-lock.js');
|
|
11
10
|
var redisLike = require('./upstash/redis-like.js');
|
|
@@ -36,10 +35,6 @@ exports.fetchPaymentId = stripeConfig.fetchPaymentId;
|
|
|
36
35
|
exports.getStripe = stripeConfig.getStripe;
|
|
37
36
|
exports.updateSubscription = stripeConfig.updateSubscription;
|
|
38
37
|
exports.validateStripeWebhook = stripeConfig.validateStripeWebhook;
|
|
39
|
-
exports.ApiAuthUtils = authUtils.ApiAuthUtils;
|
|
40
|
-
exports.getAuthenticatedUser = authUtils.getAuthenticatedUser;
|
|
41
|
-
exports.requireAuth = authUtils.requireAuth;
|
|
42
|
-
exports.requireAuthWithUser = authUtils.requireAuthWithUser;
|
|
43
38
|
exports.getQstash = upstashConfig.getQstash;
|
|
44
39
|
exports.getRedis = upstashConfig.getRedis;
|
|
45
40
|
exports.withQstash = upstashConfig.withQstash;
|
package/dist/lib/index.mjs
CHANGED
|
@@ -3,7 +3,6 @@ export { getMoneyPriceInitUserContext } from './money-price-helper.mjs';
|
|
|
3
3
|
export { fingerprintConfig } from './fingerprint-config.mjs';
|
|
4
4
|
export { creditsConfig, freeAmount, freeExpiredDays, freeRegisterAmount, oneTimeExpiredDays } from './credit-init.mjs';
|
|
5
5
|
export { ActiveSubscriptionExistsError, cancelSubscription, createCheckoutSession, createCustomerPortalSession, createOrGetCustomer, fetchPaymentId, getStripe, updateSubscription, validateStripeWebhook } from './stripe-config.mjs';
|
|
6
|
-
export { ApiAuthUtils, getAuthenticatedUser, requireAuth, requireAuthWithUser } from './auth-utils.mjs';
|
|
7
6
|
export { getQstash, getRedis, withQstash, withRedis } from './upstash-config.mjs';
|
|
8
7
|
export { acquireLock, releaseLock, withLock } from './upstash/redis-lock.mjs';
|
|
9
8
|
export { getTargetLikeCount, getUserLikedTargets, isTargetLiked, likeTarget, unlikeTarget } from './upstash/redis-like.mjs';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"money-price-helper.d.ts","sourceRoot":"","sources":["../../src/lib/money-price-helper.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"money-price-helper.d.ts","sourceRoot":"","sources":["../../src/lib/money-price-helper.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAkB5E,wBAAsB,4BAA4B,IAAI,OAAO,CAAC,eAAe,CAAC,CAuC7E"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var tslib_es6 = require('../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.js');
|
|
4
|
-
var server = require('@clerk/nextjs/server');
|
|
5
4
|
var headers = require('next/headers');
|
|
6
|
-
var server
|
|
5
|
+
var server = require('@windrun-huaiin/third-ui/fingerprint/server');
|
|
6
|
+
var authUtils = require('../auth/auth-utils.js');
|
|
7
7
|
var userContextService = require('../services/context/user-context-service.js');
|
|
8
8
|
var userContextFinalizer = require('../services/context/user-context-finalizer.js');
|
|
9
9
|
|
|
@@ -11,7 +11,7 @@ function readFingerprintIdFromRequest() {
|
|
|
11
11
|
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
12
12
|
const cookieStore = yield headers.cookies();
|
|
13
13
|
const headerList = yield headers.headers();
|
|
14
|
-
return server
|
|
14
|
+
return server.extractFingerprintFromNextStores({
|
|
15
15
|
headers: headerList,
|
|
16
16
|
cookies: cookieStore,
|
|
17
17
|
});
|
|
@@ -19,7 +19,9 @@ function readFingerprintIdFromRequest() {
|
|
|
19
19
|
}
|
|
20
20
|
function getMoneyPriceInitUserContext() {
|
|
21
21
|
return tslib_es6.__awaiter(this, void 0, void 0, function* () {
|
|
22
|
-
|
|
22
|
+
var _a;
|
|
23
|
+
const authIdentity = yield authUtils.getOptionalServerAuthIdentity();
|
|
24
|
+
const clerkUserId = (_a = authIdentity === null || authIdentity === void 0 ? void 0 : authIdentity.providerUserId) !== null && _a !== void 0 ? _a : null;
|
|
23
25
|
if (clerkUserId) {
|
|
24
26
|
const userContext = yield userContextService.fetchUserContextByClerkUserId(clerkUserId);
|
|
25
27
|
if (!userContext) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { __awaiter } from '../node_modules/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.46.2_tslib@2.8.1_typescript@5.9.3/node_modules/tslib/tslib.es6.mjs';
|
|
2
|
-
import { auth } from '@clerk/nextjs/server';
|
|
3
2
|
import { cookies, headers } from 'next/headers';
|
|
4
3
|
import { extractFingerprintFromNextStores } from '@windrun-huaiin/third-ui/fingerprint/server';
|
|
4
|
+
import { getOptionalServerAuthIdentity } from '../auth/auth-utils.mjs';
|
|
5
5
|
import { fetchUserContextByClerkUserId, buildInitUserContextFromEntities } from '../services/context/user-context-service.mjs';
|
|
6
6
|
import { finalizeUserContext } from '../services/context/user-context-finalizer.mjs';
|
|
7
7
|
|
|
@@ -17,7 +17,9 @@ function readFingerprintIdFromRequest() {
|
|
|
17
17
|
}
|
|
18
18
|
function getMoneyPriceInitUserContext() {
|
|
19
19
|
return __awaiter(this, void 0, void 0, function* () {
|
|
20
|
-
|
|
20
|
+
var _a;
|
|
21
|
+
const authIdentity = yield getOptionalServerAuthIdentity();
|
|
22
|
+
const clerkUserId = (_a = authIdentity === null || authIdentity === void 0 ? void 0 : authIdentity.providerUserId) !== null && _a !== void 0 ? _a : null;
|
|
21
23
|
if (clerkUserId) {
|
|
22
24
|
const userContext = yield fetchUserContextByClerkUserId(clerkUserId);
|
|
23
25
|
if (!userContext) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windrun-huaiin/backend-core",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.5.0",
|
|
4
4
|
"description": "Shared backend primitives: Prisma schema/client, database services, routing helpers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -47,6 +47,21 @@
|
|
|
47
47
|
"import": "./dist/lib/index.mjs",
|
|
48
48
|
"require": "./dist/lib/index.js"
|
|
49
49
|
},
|
|
50
|
+
"./auth/server": {
|
|
51
|
+
"types": "./dist/auth/auth-utils.d.ts",
|
|
52
|
+
"import": "./dist/auth/auth-utils.mjs",
|
|
53
|
+
"require": "./dist/auth/auth-utils.js"
|
|
54
|
+
},
|
|
55
|
+
"./auth/shared": {
|
|
56
|
+
"types": "./dist/auth/auth-shared.d.ts",
|
|
57
|
+
"import": "./dist/auth/auth-shared.mjs",
|
|
58
|
+
"require": "./dist/auth/auth-shared.js"
|
|
59
|
+
},
|
|
60
|
+
"./auth/middleware": {
|
|
61
|
+
"types": "./dist/auth/auth-middleware.d.ts",
|
|
62
|
+
"import": "./dist/auth/auth-middleware.mjs",
|
|
63
|
+
"require": "./dist/auth/auth-middleware.js"
|
|
64
|
+
},
|
|
50
65
|
"./app/api/webhook/stripe/route": {
|
|
51
66
|
"types": "./dist/app/api/webhook/stripe/route.d.ts",
|
|
52
67
|
"import": "./dist/app/api/webhook/stripe/route.mjs",
|
|
@@ -94,8 +109,8 @@
|
|
|
94
109
|
"stripe": "20.0.0",
|
|
95
110
|
"svix": "^1.86.0",
|
|
96
111
|
"zod": "^4.3.6",
|
|
97
|
-
"@windrun-huaiin/
|
|
98
|
-
"@windrun-huaiin/
|
|
112
|
+
"@windrun-huaiin/third-ui": "^14.5.0",
|
|
113
|
+
"@windrun-huaiin/lib": "^14.0.1"
|
|
99
114
|
},
|
|
100
115
|
"devDependencies": {
|
|
101
116
|
"@rollup/plugin-alias": "^5.1.1",
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
PaySupplier,
|
|
13
13
|
PaymentStatus
|
|
14
14
|
} from '@/db/index';
|
|
15
|
-
import { ApiAuthUtils } from '@/
|
|
15
|
+
import { ApiAuthUtils } from '@/auth/auth-utils';
|
|
16
16
|
import { getPriceConfig } from '@/lib/money-price-config';
|
|
17
17
|
|
|
18
18
|
// Request validation schema
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
createCustomerPortalSession,
|
|
5
5
|
createOrGetCustomer,
|
|
6
6
|
} from '@/lib/stripe-config';
|
|
7
|
-
import { ApiAuthUtils } from '@/
|
|
7
|
+
import { ApiAuthUtils } from '@/auth/auth-utils';
|
|
8
8
|
import { subscriptionService } from '@/db/index';
|
|
9
9
|
|
|
10
10
|
const createCustomerPortalSchema = z
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
import { anonymousAggregateService } from '@/aggregate/anonymous.aggregate.service';
|
|
9
|
+
import { getOptionalServerAuthIdentity } from '@/auth/auth-utils';
|
|
9
10
|
import type { XCredit, XSubscription, XUser } from '@windrun-huaiin/third-ui/fingerprint';
|
|
10
11
|
import { extractFingerprintFromNextRequest } from '@windrun-huaiin/third-ui/fingerprint/server';
|
|
11
|
-
import { auth } from '@clerk/nextjs/server';
|
|
12
12
|
import { NextRequest, NextResponse } from 'next/server';
|
|
13
13
|
import {
|
|
14
14
|
fetchLatestUserContextByFingerprintId,
|
|
@@ -650,7 +650,8 @@ async function handleFingerprintRequest(request: NextRequest, options: { createI
|
|
|
650
650
|
}
|
|
651
651
|
console.log('Received fingerprintId:', fingerprintId);
|
|
652
652
|
|
|
653
|
-
const
|
|
653
|
+
const authIdentity = await getOptionalServerAuthIdentity();
|
|
654
|
+
const clerkUserId = authIdentity?.providerUserId ?? null;
|
|
654
655
|
try {
|
|
655
656
|
// 优先根据 Clerk ID 查询(如果已登录)
|
|
656
657
|
let existingUserResult: XUserResponse | null = null;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { ClerkMiddlewareAuth } from '@clerk/nextjs/server';
|
|
2
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
3
|
+
import { AUTH_HEADERS, type ProviderIdentity } from './auth-shared';
|
|
4
|
+
|
|
5
|
+
export function buildProtectedPageRoutePatterns(
|
|
6
|
+
protectedRoots: readonly string[],
|
|
7
|
+
locales: readonly string[]
|
|
8
|
+
): string[] {
|
|
9
|
+
const uniqueRoots = [...new Set(protectedRoots)]
|
|
10
|
+
.map((root) => root.trim())
|
|
11
|
+
.filter(Boolean)
|
|
12
|
+
.map((root) => (root.startsWith('/') ? root : `/${root}`))
|
|
13
|
+
.map((root) => root.replace(/\/+$/, ''));
|
|
14
|
+
|
|
15
|
+
const uniqueLocales = [...new Set(locales)]
|
|
16
|
+
.map((locale) => locale.trim())
|
|
17
|
+
.filter(Boolean);
|
|
18
|
+
|
|
19
|
+
const patterns = new Set<string>();
|
|
20
|
+
|
|
21
|
+
for (const root of uniqueRoots) {
|
|
22
|
+
patterns.add(`${root}(.*)`);
|
|
23
|
+
|
|
24
|
+
for (const locale of uniqueLocales) {
|
|
25
|
+
patterns.add(`/${locale}${root}(.*)`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return [...patterns];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface AuthMiddlewareOptions {
|
|
33
|
+
protectedPageRoutes: (req: NextRequest) => boolean;
|
|
34
|
+
protectedApiRoutes: (req: NextRequest) => boolean;
|
|
35
|
+
publicApiRoutes: (req: NextRequest) => boolean;
|
|
36
|
+
intlMiddleware: (req: NextRequest) => ReturnType<typeof NextResponse.next> | Response | undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function authenticateWithClerk(auth: ClerkMiddlewareAuth): Promise<ProviderIdentity | null> {
|
|
40
|
+
const { userId } = await auth();
|
|
41
|
+
if (!userId) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
provider: 'clerk',
|
|
47
|
+
providerUserId: userId,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function buildAuthenticatedRequestHeaders(
|
|
52
|
+
req: NextRequest,
|
|
53
|
+
auth: ProviderIdentity
|
|
54
|
+
): Headers {
|
|
55
|
+
const headers = new Headers(req.headers);
|
|
56
|
+
headers.set(AUTH_HEADERS.provider, auth.provider);
|
|
57
|
+
headers.set(AUTH_HEADERS.providerUserId, auth.providerUserId);
|
|
58
|
+
return headers;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function handleAuthMiddleware(
|
|
62
|
+
auth: ClerkMiddlewareAuth,
|
|
63
|
+
req: NextRequest,
|
|
64
|
+
options: AuthMiddlewareOptions
|
|
65
|
+
) {
|
|
66
|
+
const { protectedPageRoutes, protectedApiRoutes, publicApiRoutes, intlMiddleware } = options;
|
|
67
|
+
|
|
68
|
+
if (protectedPageRoutes(req)) {
|
|
69
|
+
const identity = await authenticateWithClerk(auth);
|
|
70
|
+
if (!identity) {
|
|
71
|
+
return (await auth()).redirectToSignIn();
|
|
72
|
+
}
|
|
73
|
+
const requestHeaders = buildAuthenticatedRequestHeaders(req, identity);
|
|
74
|
+
console.log('Forward auth context for protected page:', identity.provider, identity.providerUserId);
|
|
75
|
+
return intlMiddleware(
|
|
76
|
+
new NextRequest(req.url, {
|
|
77
|
+
headers: requestHeaders,
|
|
78
|
+
method: req.method,
|
|
79
|
+
body: req.body,
|
|
80
|
+
})
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (protectedApiRoutes(req)) {
|
|
85
|
+
const identity = await authenticateWithClerk(auth);
|
|
86
|
+
if (!identity) {
|
|
87
|
+
return (await auth()).redirectToSignIn();
|
|
88
|
+
}
|
|
89
|
+
const requestHeaders = buildAuthenticatedRequestHeaders(req, identity);
|
|
90
|
+
console.log('Forward auth context for protected API:', identity.provider, identity.providerUserId);
|
|
91
|
+
return NextResponse.next({
|
|
92
|
+
request: {
|
|
93
|
+
headers: requestHeaders,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (publicApiRoutes(req)) {
|
|
99
|
+
console.log('Public API route, no auth required:', req.nextUrl.pathname);
|
|
100
|
+
return NextResponse.next();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (req.nextUrl.pathname.startsWith('/api/')) {
|
|
104
|
+
console.log('Other API route, no internationalization:', req.nextUrl.pathname);
|
|
105
|
+
return NextResponse.next();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const AUTH_HEADERS = {
|
|
2
|
+
provider: 'x-auth-provider',
|
|
3
|
+
providerUserId: 'x-auth-provider-user-id',
|
|
4
|
+
} as const;
|
|
5
|
+
|
|
6
|
+
export const AUTH_ERRORS = {
|
|
7
|
+
unauthorized: 'UNAUTHORIZED',
|
|
8
|
+
userNotFound: 'USER_NOT_FOUND',
|
|
9
|
+
} as const;
|
|
10
|
+
|
|
11
|
+
export type AuthProvider = 'clerk';
|
|
12
|
+
|
|
13
|
+
export interface ProviderIdentity {
|
|
14
|
+
provider: AuthProvider;
|
|
15
|
+
providerUserId: string;
|
|
16
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { NextRequest } from 'next/server';
|
|
2
|
+
import { auth } from '@clerk/nextjs/server';
|
|
2
3
|
import { userService } from '../services/database/index';
|
|
3
4
|
import { User } from '../services/database/prisma-model-type';
|
|
5
|
+
import { AUTH_ERRORS, AUTH_HEADERS, type AuthProvider, type ProviderIdentity } from './auth-shared';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* 认证结果类型
|
|
@@ -8,7 +10,8 @@ import { User } from '../services/database/prisma-model-type';
|
|
|
8
10
|
export interface AuthResult {
|
|
9
11
|
userId: string;
|
|
10
12
|
user: User;
|
|
11
|
-
|
|
13
|
+
provider: AuthProvider;
|
|
14
|
+
providerUserId: string;
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
/**
|
|
@@ -16,20 +19,22 @@ export interface AuthResult {
|
|
|
16
19
|
*/
|
|
17
20
|
export async function getAuthenticatedUser(req: NextRequest): Promise<AuthResult> {
|
|
18
21
|
try {
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
const provider = req.headers.get(AUTH_HEADERS.provider);
|
|
23
|
+
const providerUserId = req.headers.get(AUTH_HEADERS.providerUserId);
|
|
24
|
+
if (provider !== 'clerk' || !providerUserId) {
|
|
25
|
+
throw new Error(AUTH_ERRORS.unauthorized);
|
|
22
26
|
}
|
|
23
|
-
|
|
24
|
-
const user = await userService.findByClerkUserId(
|
|
27
|
+
|
|
28
|
+
const user = await userService.findByClerkUserId(providerUserId);
|
|
25
29
|
if (!user) {
|
|
26
|
-
throw new Error(
|
|
30
|
+
throw new Error(AUTH_ERRORS.userNotFound);
|
|
27
31
|
}
|
|
28
|
-
|
|
32
|
+
|
|
29
33
|
return {
|
|
30
34
|
userId: user.userId,
|
|
31
35
|
user,
|
|
32
|
-
|
|
36
|
+
provider: 'clerk',
|
|
37
|
+
providerUserId,
|
|
33
38
|
};
|
|
34
39
|
} catch (error) {
|
|
35
40
|
console.error('Error getting authenticated user:', error);
|
|
@@ -52,6 +57,55 @@ export async function requireAuthWithUser(req: NextRequest): Promise<AuthResult>
|
|
|
52
57
|
return await getAuthenticatedUser(req);
|
|
53
58
|
}
|
|
54
59
|
|
|
60
|
+
/**
|
|
61
|
+
* 服务端场景下获取当前已认证身份(如果存在)
|
|
62
|
+
* 适用于只依赖登录态、不需要查询业务用户的逻辑
|
|
63
|
+
*/
|
|
64
|
+
export async function getOptionalServerAuthIdentity(): Promise<ProviderIdentity | null> {
|
|
65
|
+
try {
|
|
66
|
+
const { userId: providerUserId } = await auth();
|
|
67
|
+
if (!providerUserId) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
provider: 'clerk',
|
|
73
|
+
providerUserId,
|
|
74
|
+
};
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.error('Error getting optional server auth identity:', error);
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 服务端场景下获取当前已认证用户(如果存在)
|
|
83
|
+
* 适用于 Server Component / Server Action 中基于登录态控制展示的逻辑
|
|
84
|
+
*/
|
|
85
|
+
export async function getOptionalServerAuthUser(): Promise<AuthResult | null> {
|
|
86
|
+
try {
|
|
87
|
+
const identity = await getOptionalServerAuthIdentity();
|
|
88
|
+
if (!identity) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const user = await userService.findByClerkUserId(identity.providerUserId);
|
|
93
|
+
if (!user) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
userId: user.userId,
|
|
99
|
+
user,
|
|
100
|
+
provider: identity.provider,
|
|
101
|
+
providerUserId: identity.providerUserId,
|
|
102
|
+
};
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error('Error getting optional server auth user:', error);
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
55
109
|
/**
|
|
56
110
|
* API Route版本的认证工具函数
|
|
57
111
|
*/
|
|
@@ -98,4 +152,4 @@ export class ApiAuthUtils {
|
|
|
98
152
|
return null;
|
|
99
153
|
}
|
|
100
154
|
}
|
|
101
|
-
}
|
|
155
|
+
}
|
package/src/lib/index.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { auth } from '@clerk/nextjs/server';
|
|
2
1
|
import { cookies, headers } from 'next/headers';
|
|
3
2
|
import {
|
|
4
3
|
extractFingerprintFromNextStores,
|
|
5
4
|
} from '@windrun-huaiin/third-ui/fingerprint/server';
|
|
6
5
|
import type { InitUserContext } from '@windrun-huaiin/third-ui/main/server';
|
|
6
|
+
import { getOptionalServerAuthIdentity } from '../auth/auth-utils';
|
|
7
7
|
import {
|
|
8
8
|
buildInitUserContextFromEntities,
|
|
9
9
|
fetchUserContextByClerkUserId,
|
|
@@ -21,7 +21,8 @@ async function readFingerprintIdFromRequest(): Promise<string | null> {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export async function getMoneyPriceInitUserContext(): Promise<InitUserContext> {
|
|
24
|
-
const
|
|
24
|
+
const authIdentity = await getOptionalServerAuthIdentity();
|
|
25
|
+
const clerkUserId = authIdentity?.providerUserId ?? null;
|
|
25
26
|
|
|
26
27
|
if (clerkUserId) {
|
|
27
28
|
const userContext = await fetchUserContextByClerkUserId(clerkUserId);
|