fix: 全服务注册 JwtStrategy + 修复微信 WxApi 未配置 crash
**后端** - 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 <noreply@anthropic.com>
This commit is contained in:
parent
6bdd8d1e19
commit
75ed31cc04
|
|
@ -8,6 +8,9 @@ export * from './decorators/roles.decorator';
|
||||||
export * from './guards/jwt-auth.guard';
|
export * from './guards/jwt-auth.guard';
|
||||||
export * from './guards/roles.guard';
|
export * from './guards/roles.guard';
|
||||||
|
|
||||||
|
// Strategies
|
||||||
|
export * from './strategies/jwt.strategy';
|
||||||
|
|
||||||
// Interceptors
|
// Interceptors
|
||||||
export * from './interceptors/logging.interceptor';
|
export * from './interceptors/logging.interceptor';
|
||||||
export * from './interceptors/transform.interceptor';
|
export * from './interceptors/transform.interceptor';
|
||||||
|
|
|
||||||
|
|
@ -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 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ import { Module } from '@nestjs/common';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { PassportModule } from '@nestjs/passport';
|
import { PassportModule } from '@nestjs/passport';
|
||||||
import { JwtModule } from '@nestjs/jwt';
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
|
import { JwtStrategy } from '@genex/common';
|
||||||
|
|
||||||
// Domain entities
|
// Domain entities
|
||||||
import { Settlement } from './domain/entities/settlement.entity';
|
import { Settlement } from './domain/entities/settlement.entity';
|
||||||
|
|
@ -44,6 +45,7 @@ import { AdminReportsController } from './interface/http/controllers/admin-repor
|
||||||
],
|
],
|
||||||
controllers: [ClearingController, AdminFinanceController, AdminReportsController],
|
controllers: [ClearingController, AdminFinanceController, AdminReportsController],
|
||||||
providers: [
|
providers: [
|
||||||
|
JwtStrategy,
|
||||||
// Repository DI bindings (interface -> implementation)
|
// Repository DI bindings (interface -> implementation)
|
||||||
{ provide: SETTLEMENT_REPOSITORY, useClass: SettlementRepository },
|
{ provide: SETTLEMENT_REPOSITORY, useClass: SettlementRepository },
|
||||||
{ provide: REFUND_REPOSITORY, useClass: RefundRepository },
|
{ provide: REFUND_REPOSITORY, useClass: RefundRepository },
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { Module } from '@nestjs/common';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { PassportModule } from '@nestjs/passport';
|
import { PassportModule } from '@nestjs/passport';
|
||||||
import { JwtModule } from '@nestjs/jwt';
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
|
import { JwtStrategy } from '@genex/common';
|
||||||
|
|
||||||
// ─── Domain Entities ───
|
// ─── Domain Entities ───
|
||||||
import { AmlAlert } from './domain/entities/aml-alert.entity';
|
import { AmlAlert } from './domain/entities/aml-alert.entity';
|
||||||
|
|
@ -75,6 +76,7 @@ import { AdminInsuranceController } from './interface/http/controllers/admin-ins
|
||||||
AdminInsuranceController,
|
AdminInsuranceController,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
JwtStrategy,
|
||||||
// ─── Repository DI bindings (interface → implementation) ───
|
// ─── Repository DI bindings (interface → implementation) ───
|
||||||
{ provide: AML_ALERT_REPOSITORY, useClass: AmlAlertRepository },
|
{ provide: AML_ALERT_REPOSITORY, useClass: AmlAlertRepository },
|
||||||
{ provide: OFAC_SCREENING_REPOSITORY, useClass: OfacScreeningRepository },
|
{ provide: OFAC_SCREENING_REPOSITORY, useClass: OfacScreeningRepository },
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { Module } from '@nestjs/common';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { PassportModule } from '@nestjs/passport';
|
import { PassportModule } from '@nestjs/passport';
|
||||||
import { JwtModule } from '@nestjs/jwt';
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
|
import { JwtStrategy } from '@genex/common';
|
||||||
|
|
||||||
// Domain entities
|
// Domain entities
|
||||||
import { Issuer } from './domain/entities/issuer.entity';
|
import { Issuer } from './domain/entities/issuer.entity';
|
||||||
|
|
@ -88,6 +89,7 @@ import { RolesGuard } from './interface/http/guards/roles.guard';
|
||||||
CouponBatchController,
|
CouponBatchController,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
JwtStrategy,
|
||||||
// Infrastructure -> Domain port binding (Repository pattern)
|
// Infrastructure -> Domain port binding (Repository pattern)
|
||||||
{ provide: ISSUER_REPOSITORY, useClass: IssuerRepository },
|
{ provide: ISSUER_REPOSITORY, useClass: IssuerRepository },
|
||||||
{ provide: COUPON_REPOSITORY, useClass: CouponRepository },
|
{ provide: COUPON_REPOSITORY, useClass: CouponRepository },
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { Module } from '@nestjs/common';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { PassportModule } from '@nestjs/passport';
|
import { PassportModule } from '@nestjs/passport';
|
||||||
import { JwtModule } from '@nestjs/jwt';
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
|
import { JwtStrategy } from '@genex/common';
|
||||||
|
|
||||||
// Domain entities
|
// Domain entities
|
||||||
import { Notification } from './domain/entities/notification.entity';
|
import { Notification } from './domain/entities/notification.entity';
|
||||||
|
|
@ -94,6 +95,7 @@ import { DeviceTokenController } from './interface/http/controllers/device-token
|
||||||
DeviceTokenController,
|
DeviceTokenController,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
JwtStrategy,
|
||||||
// Infrastructure -> Domain repository binding
|
// Infrastructure -> Domain repository binding
|
||||||
{ provide: NOTIFICATION_REPOSITORY, useClass: NotificationRepository },
|
{ provide: NOTIFICATION_REPOSITORY, useClass: NotificationRepository },
|
||||||
{ provide: ANNOUNCEMENT_REPOSITORY, useClass: AnnouncementRepositoryImpl },
|
{ provide: ANNOUNCEMENT_REPOSITORY, useClass: AnnouncementRepositoryImpl },
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { JwtModule } from '@nestjs/jwt';
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
import { PassportModule } from '@nestjs/passport';
|
import { PassportModule } from '@nestjs/passport';
|
||||||
import { ScheduleModule } from '@nestjs/schedule';
|
import { ScheduleModule } from '@nestjs/schedule';
|
||||||
|
import { JwtStrategy } from '@genex/common';
|
||||||
|
|
||||||
// Domain entities
|
// Domain entities
|
||||||
import { TelemetryEvent } from './domain/entities/telemetry-event.entity';
|
import { TelemetryEvent } from './domain/entities/telemetry-event.entity';
|
||||||
|
|
@ -72,6 +73,7 @@ import { HealthController } from './interface/http/controllers/health.controller
|
||||||
HealthController,
|
HealthController,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
JwtStrategy,
|
||||||
{ provide: TELEMETRY_EVENT_REPOSITORY, useClass: TelemetryEventRepository },
|
{ provide: TELEMETRY_EVENT_REPOSITORY, useClass: TelemetryEventRepository },
|
||||||
{ provide: ONLINE_SNAPSHOT_REPOSITORY, useClass: OnlineSnapshotRepository },
|
{ provide: ONLINE_SNAPSHOT_REPOSITORY, useClass: OnlineSnapshotRepository },
|
||||||
{ provide: DAILY_ACTIVE_STATS_REPOSITORY, useClass: DailyActiveStatsRepository },
|
{ provide: DAILY_ACTIVE_STATS_REPOSITORY, useClass: DailyActiveStatsRepository },
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { Module } from '@nestjs/common';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { JwtModule } from '@nestjs/jwt';
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
import { PassportModule } from '@nestjs/passport';
|
import { PassportModule } from '@nestjs/passport';
|
||||||
|
import { JwtStrategy } from '@genex/common';
|
||||||
|
|
||||||
// Domain entities
|
// Domain entities
|
||||||
import { User } from './domain/entities/user.entity';
|
import { User } from './domain/entities/user.entity';
|
||||||
|
|
@ -59,6 +60,7 @@ import { AdminAnalyticsController } from './interface/http/controllers/admin-ana
|
||||||
AdminDashboardController, AdminUserController, AdminSystemController, AdminAnalyticsController,
|
AdminDashboardController, AdminUserController, AdminSystemController, AdminAnalyticsController,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
JwtStrategy,
|
||||||
// Infrastructure -> Domain port binding
|
// Infrastructure -> Domain port binding
|
||||||
{ provide: USER_REPOSITORY, useClass: UserRepository },
|
{ provide: USER_REPOSITORY, useClass: UserRepository },
|
||||||
{ provide: KYC_REPOSITORY, useClass: KycRepository },
|
{ provide: KYC_REPOSITORY, useClass: KycRepository },
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,12 @@ class _WelcomePageState extends ConsumerState<WelcomePage> {
|
||||||
// ── 微信 ─────────────────────────────────────────────────────────────────
|
// ── 微信 ─────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
Future<void> _onWechatTap() async {
|
Future<void> _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 (!installed) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue