From 75ed31cc041623ff91d2268d22973adb5fdd5463 Mon Sep 17 00:00:00 2001 From: hailin Date: Wed, 4 Mar 2026 22:24:07 -0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=85=A8=E6=9C=8D=E5=8A=A1=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=20JwtStrategy=20+=20=E4=BF=AE=E5=A4=8D=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=20WxApi=20=E6=9C=AA=E9=85=8D=E7=BD=AE=20crash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **后端** - packages/common: 新增并导出 JwtStrategy(共享 Passport JWT 策略) - 6 个服务模块(user/issuer/clearing/compliance/notification/telemetry) 均缺少 JwtStrategy provider,导致所有受保护接口返回 500 "Unknown authentication strategy jwt" - 统一修复:各模块 providers 添加 JwtStrategy **Flutter** - welcome_page: _onWechatTap() 的 isWeChatInstalled 调用未设 WECHAT_APP_ID 时会抛出 PlatformException,catch 后降级为"未安装"提示 Co-Authored-By: Claude Sonnet 4.6 --- backend/packages/common/src/index.ts | 3 +++ .../common/src/strategies/jwt.strategy.ts | 25 +++++++++++++++++++ .../clearing-service/src/clearing.module.ts | 2 ++ .../src/compliance.module.ts | 2 ++ .../issuer-service/src/issuer.module.ts | 2 ++ .../src/notification.module.ts | 2 ++ .../telemetry-service/src/telemetry.module.ts | 2 ++ .../services/user-service/src/user.module.ts | 2 ++ .../auth/presentation/pages/welcome_page.dart | 7 +++++- 9 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 backend/packages/common/src/strategies/jwt.strategy.ts diff --git a/backend/packages/common/src/index.ts b/backend/packages/common/src/index.ts index 963ebb6..4972a34 100644 --- a/backend/packages/common/src/index.ts +++ b/backend/packages/common/src/index.ts @@ -8,6 +8,9 @@ export * from './decorators/roles.decorator'; export * from './guards/jwt-auth.guard'; export * from './guards/roles.guard'; +// Strategies +export * from './strategies/jwt.strategy'; + // Interceptors export * from './interceptors/logging.interceptor'; export * from './interceptors/transform.interceptor'; diff --git a/backend/packages/common/src/strategies/jwt.strategy.ts b/backend/packages/common/src/strategies/jwt.strategy.ts new file mode 100644 index 0000000..ee86497 --- /dev/null +++ b/backend/packages/common/src/strategies/jwt.strategy.ts @@ -0,0 +1,25 @@ +import { Injectable } from '@nestjs/common'; +import { PassportStrategy } from '@nestjs/passport'; +import { ExtractJwt, Strategy } from 'passport-jwt'; + +/** + * Shared JWT Passport Strategy. + * Register as a provider in each service module that uses JwtAuthGuard. + * + * Usage in module: + * providers: [JwtStrategy, ...] + */ +@Injectable() +export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') { + constructor() { + super({ + jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), + ignoreExpiration: false, + secretOrKey: process.env.JWT_ACCESS_SECRET || 'dev-access-secret', + }); + } + + async validate(payload: { sub: string; role: string; kycLevel: number; type: string }) { + return { sub: payload.sub, role: payload.role, kycLevel: payload.kycLevel }; + } +} diff --git a/backend/services/clearing-service/src/clearing.module.ts b/backend/services/clearing-service/src/clearing.module.ts index dfe49c7..ddd988b 100644 --- a/backend/services/clearing-service/src/clearing.module.ts +++ b/backend/services/clearing-service/src/clearing.module.ts @@ -2,6 +2,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { PassportModule } from '@nestjs/passport'; import { JwtModule } from '@nestjs/jwt'; +import { JwtStrategy } from '@genex/common'; // Domain entities import { Settlement } from './domain/entities/settlement.entity'; @@ -44,6 +45,7 @@ import { AdminReportsController } from './interface/http/controllers/admin-repor ], controllers: [ClearingController, AdminFinanceController, AdminReportsController], providers: [ + JwtStrategy, // Repository DI bindings (interface -> implementation) { provide: SETTLEMENT_REPOSITORY, useClass: SettlementRepository }, { provide: REFUND_REPOSITORY, useClass: RefundRepository }, diff --git a/backend/services/compliance-service/src/compliance.module.ts b/backend/services/compliance-service/src/compliance.module.ts index 4596205..c3fae88 100644 --- a/backend/services/compliance-service/src/compliance.module.ts +++ b/backend/services/compliance-service/src/compliance.module.ts @@ -2,6 +2,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { PassportModule } from '@nestjs/passport'; import { JwtModule } from '@nestjs/jwt'; +import { JwtStrategy } from '@genex/common'; // ─── Domain Entities ─── import { AmlAlert } from './domain/entities/aml-alert.entity'; @@ -75,6 +76,7 @@ import { AdminInsuranceController } from './interface/http/controllers/admin-ins AdminInsuranceController, ], providers: [ + JwtStrategy, // ─── Repository DI bindings (interface → implementation) ─── { provide: AML_ALERT_REPOSITORY, useClass: AmlAlertRepository }, { provide: OFAC_SCREENING_REPOSITORY, useClass: OfacScreeningRepository }, diff --git a/backend/services/issuer-service/src/issuer.module.ts b/backend/services/issuer-service/src/issuer.module.ts index abf5247..e2e9b2f 100644 --- a/backend/services/issuer-service/src/issuer.module.ts +++ b/backend/services/issuer-service/src/issuer.module.ts @@ -2,6 +2,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { PassportModule } from '@nestjs/passport'; import { JwtModule } from '@nestjs/jwt'; +import { JwtStrategy } from '@genex/common'; // Domain entities import { Issuer } from './domain/entities/issuer.entity'; @@ -88,6 +89,7 @@ import { RolesGuard } from './interface/http/guards/roles.guard'; CouponBatchController, ], providers: [ + JwtStrategy, // Infrastructure -> Domain port binding (Repository pattern) { provide: ISSUER_REPOSITORY, useClass: IssuerRepository }, { provide: COUPON_REPOSITORY, useClass: CouponRepository }, diff --git a/backend/services/notification-service/src/notification.module.ts b/backend/services/notification-service/src/notification.module.ts index 789036e..b43f2be 100644 --- a/backend/services/notification-service/src/notification.module.ts +++ b/backend/services/notification-service/src/notification.module.ts @@ -2,6 +2,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { PassportModule } from '@nestjs/passport'; import { JwtModule } from '@nestjs/jwt'; +import { JwtStrategy } from '@genex/common'; // Domain entities import { Notification } from './domain/entities/notification.entity'; @@ -94,6 +95,7 @@ import { DeviceTokenController } from './interface/http/controllers/device-token DeviceTokenController, ], providers: [ + JwtStrategy, // Infrastructure -> Domain repository binding { provide: NOTIFICATION_REPOSITORY, useClass: NotificationRepository }, { provide: ANNOUNCEMENT_REPOSITORY, useClass: AnnouncementRepositoryImpl }, diff --git a/backend/services/telemetry-service/src/telemetry.module.ts b/backend/services/telemetry-service/src/telemetry.module.ts index f40346e..ff407db 100644 --- a/backend/services/telemetry-service/src/telemetry.module.ts +++ b/backend/services/telemetry-service/src/telemetry.module.ts @@ -3,6 +3,7 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { JwtModule } from '@nestjs/jwt'; import { PassportModule } from '@nestjs/passport'; import { ScheduleModule } from '@nestjs/schedule'; +import { JwtStrategy } from '@genex/common'; // Domain entities import { TelemetryEvent } from './domain/entities/telemetry-event.entity'; @@ -72,6 +73,7 @@ import { HealthController } from './interface/http/controllers/health.controller HealthController, ], providers: [ + JwtStrategy, { provide: TELEMETRY_EVENT_REPOSITORY, useClass: TelemetryEventRepository }, { provide: ONLINE_SNAPSHOT_REPOSITORY, useClass: OnlineSnapshotRepository }, { provide: DAILY_ACTIVE_STATS_REPOSITORY, useClass: DailyActiveStatsRepository }, diff --git a/backend/services/user-service/src/user.module.ts b/backend/services/user-service/src/user.module.ts index 65c275a..59d147f 100644 --- a/backend/services/user-service/src/user.module.ts +++ b/backend/services/user-service/src/user.module.ts @@ -2,6 +2,7 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { JwtModule } from '@nestjs/jwt'; import { PassportModule } from '@nestjs/passport'; +import { JwtStrategy } from '@genex/common'; // Domain entities import { User } from './domain/entities/user.entity'; @@ -59,6 +60,7 @@ import { AdminAnalyticsController } from './interface/http/controllers/admin-ana AdminDashboardController, AdminUserController, AdminSystemController, AdminAnalyticsController, ], providers: [ + JwtStrategy, // Infrastructure -> Domain port binding { provide: USER_REPOSITORY, useClass: UserRepository }, { provide: KYC_REPOSITORY, useClass: KycRepository }, diff --git a/frontend/genex-mobile/lib/features/auth/presentation/pages/welcome_page.dart b/frontend/genex-mobile/lib/features/auth/presentation/pages/welcome_page.dart index c763e38..a17aff9 100644 --- a/frontend/genex-mobile/lib/features/auth/presentation/pages/welcome_page.dart +++ b/frontend/genex-mobile/lib/features/auth/presentation/pages/welcome_page.dart @@ -78,7 +78,12 @@ class _WelcomePageState extends ConsumerState { // ── 微信 ───────────────────────────────────────────────────────────────── Future _onWechatTap() async { - final installed = await _fluwx.isWeChatInstalled; + bool installed = false; + try { + installed = await _fluwx.isWeChatInstalled; + } catch (_) { + // WxApi not configured (WECHAT_APP_ID not provided) — treat as not installed + } if (!installed) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar(