用户静默注册
This commit is contained in:
@@ -12,6 +12,7 @@ export interface AuthUser {
|
||||
actorId: bigint;
|
||||
clientApp: ClientApp;
|
||||
sub: string;
|
||||
phoneVerified: boolean;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@@ -39,6 +40,7 @@ export class JwtAuthGuard implements CanActivate {
|
||||
actorId: BigInt(payload.actorId),
|
||||
clientApp,
|
||||
sub: payload.sub,
|
||||
phoneVerified: !!payload.phoneVerified,
|
||||
} satisfies AuthUser;
|
||||
return true;
|
||||
} catch (err) {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import {
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
Injectable,
|
||||
} from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { CLIENT_APP_ACTOR_MAP, ClientApp } from '@dukang/shared-types';
|
||||
import type { AuthUser } from './jwt-auth.guard';
|
||||
|
||||
@Injectable()
|
||||
export class OptionalJwtAuthGuard implements CanActivate {
|
||||
constructor(private readonly jwtService: JwtService) {}
|
||||
|
||||
canActivate(context: ExecutionContext): boolean {
|
||||
const req = context.switchToHttp().getRequest();
|
||||
const auth = req.headers.authorization as string | undefined;
|
||||
if (!auth?.startsWith('Bearer ')) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
const payload = this.jwtService.verify(auth.slice(7));
|
||||
const clientApp = req.headers['x-client-app'] as ClientApp;
|
||||
if (!clientApp || payload.clientApp !== clientApp) return true;
|
||||
const expectedActor = CLIENT_APP_ACTOR_MAP[clientApp];
|
||||
if (payload.actorType !== expectedActor) return true;
|
||||
req.user = {
|
||||
actorType: payload.actorType,
|
||||
actorId: BigInt(payload.actorId),
|
||||
clientApp,
|
||||
sub: payload.sub,
|
||||
phoneVerified: !!payload.phoneVerified,
|
||||
} satisfies AuthUser;
|
||||
} catch {
|
||||
/* ignore invalid token */
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import {
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
ForbiddenException,
|
||||
Injectable,
|
||||
} from '@nestjs/common';
|
||||
import { PrismaService } from '../prisma/prisma.module';
|
||||
import type { AuthUser } from './jwt-auth.guard';
|
||||
|
||||
@Injectable()
|
||||
export class PhoneVerifiedGuard implements CanActivate {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const req = context.switchToHttp().getRequest();
|
||||
const user = req.user as AuthUser | undefined;
|
||||
if (!user || user.actorType !== 'USER') {
|
||||
throw new ForbiddenException('请先验证手机号');
|
||||
}
|
||||
|
||||
const row = await this.prisma.user.findUnique({
|
||||
where: { id: user.actorId },
|
||||
select: { phoneVerifiedAt: true, mergedIntoUserId: true, status: true },
|
||||
});
|
||||
if (!row || row.status !== 1 || row.mergedIntoUserId) {
|
||||
throw new ForbiddenException('账号状态异常,请重新进入');
|
||||
}
|
||||
if (!row.phoneVerifiedAt) {
|
||||
throw new ForbiddenException('请先验证手机号');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user