rwadurian/backend/services/authorization-service/src/pre-planting/pre-planting-guard.intercep...

82 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
ForbiddenException,
Logger,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { PrePlantingClient } from './pre-planting.client';
/**
* 预种授权申请拦截器
*
* 仅拦截用户端授权申请路由POST /authorizations/...
* 规则:
* - 无预种记录(纯认种用户)→ 直接放行
* - 有预种记录且已合并成树 → 放行
* - 有预种记录但未合并 → 拦截
* - planting-service 不可达 → 放行fail-open不影响现有功能
*/
@Injectable()
export class PrePlantingAuthorizationInterceptor implements NestInterceptor {
private readonly logger = new Logger(PrePlantingAuthorizationInterceptor.name);
private readonly protectedPaths = [
'/authorizations/community',
'/authorizations/province',
'/authorizations/city',
'/authorizations/self-apply',
];
constructor(private readonly client: PrePlantingClient) {}
async intercept(
context: ExecutionContext,
next: CallHandler,
): Promise<Observable<unknown>> {
const req = context.switchToHttp().getRequest();
// 仅拦截 POST 请求
if (req.method !== 'POST') {
return next.handle();
}
// 仅拦截特定路由
const reqPath: string = req.path || req.url || '';
if (!this.protectedPaths.some((p) => reqPath.endsWith(p))) {
return next.handle();
}
const accountSequence = req.user?.accountSequence;
if (!accountSequence) {
return next.handle();
}
try {
const eligibility = await this.client.getEligibility(accountSequence);
// 无预种记录 → 纯认种用户,直接放行
if (!eligibility.hasPrePlanting) {
return next.handle();
}
// 有预种但未满足条件 → 拦截
if (!eligibility.canApplyAuthorization) {
throw new ForbiddenException(
'须累积购买5份预种计划合并成树后方可申请授权',
);
}
} catch (error) {
if (error instanceof ForbiddenException) throw error;
// planting-service 不可达,默认放行
this.logger.warn(
`[PRE-PLANTING] Failed to check eligibility for ${accountSequence}, allowing through`,
);
}
return next.handle();
}
}