feat(api): 账户资料与密码安全

This commit is contained in:
R524809
2026-09-03 16:56:20 +08:00
parent 46d98ab11e
commit a5b89ddb1d
13 changed files with 552 additions and 14 deletions
@@ -9,8 +9,8 @@ import { Redis } from 'ioredis';
import { ApiError } from '../common/api-error.js';
import { APP_CONFIG, type AppConfig } from '../config/app-config.module.js';
type AuthAction = 'login' | 'register' | 'refresh';
type Limit = { ip: number; email?: number };
type AuthAction = 'login' | 'register' | 'refresh' | 'change_password';
type Limit = { ip: number; email?: number; user?: number };
@Injectable()
export class AuthRateLimiter implements OnModuleInit, OnModuleDestroy {
@@ -32,7 +32,7 @@ export class AuthRateLimiter implements OnModuleInit, OnModuleDestroy {
public async consume(
action: AuthAction,
identifiers: { ip: string | null; email?: string },
identifiers: { ip: string | null; email?: string; userId?: string },
): Promise<void> {
const limit = this.limitFor(action);
await this.consumeBucket(
@@ -49,6 +49,14 @@ export class AuthRateLimiter implements OnModuleInit, OnModuleDestroy {
limit.email,
);
}
if (identifiers.userId && limit.user) {
await this.consumeBucket(
action,
'user',
identifiers.userId,
limit.user,
);
}
}
public async onModuleDestroy(): Promise<void> {
@@ -61,7 +69,7 @@ export class AuthRateLimiter implements OnModuleInit, OnModuleDestroy {
private async consumeBucket(
action: AuthAction,
dimension: 'ip' | 'email',
dimension: 'ip' | 'email' | 'user',
identifier: string,
limit: number,
): Promise<void> {
@@ -112,6 +120,12 @@ export class AuthRateLimiter implements OnModuleInit, OnModuleDestroy {
email: this.config.AUTH_REGISTER_EMAIL_LIMIT,
};
}
if (action === 'change_password') {
return {
ip: this.config.AUTH_CHANGE_PASSWORD_IP_LIMIT,
user: this.config.AUTH_CHANGE_PASSWORD_USER_LIMIT,
};
}
return { ip: this.config.AUTH_REFRESH_IP_LIMIT };
}
}