2026-01-16 11:26:02 +08:00
|
|
|
|
import {
|
|
|
|
|
|
CanActivate,
|
|
|
|
|
|
ExecutionContext,
|
|
|
|
|
|
Injectable,
|
|
|
|
|
|
UnauthorizedException,
|
2026-01-18 15:44:37 +08:00
|
|
|
|
Logger,
|
2026-01-16 11:26:02 +08:00
|
|
|
|
} from '@nestjs/common';
|
|
|
|
|
|
import { ConfigService } from '@nestjs/config';
|
|
|
|
|
|
import { Request } from 'express';
|
2026-01-18 12:47:16 +08:00
|
|
|
|
import { UsersService } from '../../users/users.service';
|
2026-01-16 11:26:02 +08:00
|
|
|
|
|
|
|
|
|
|
@Injectable()
|
|
|
|
|
|
export class AuthGuard implements CanActivate {
|
2026-01-18 15:44:37 +08:00
|
|
|
|
private readonly logger = new Logger(AuthGuard.name);
|
|
|
|
|
|
|
2026-01-18 12:47:16 +08:00
|
|
|
|
constructor(
|
|
|
|
|
|
private configService: ConfigService,
|
|
|
|
|
|
private usersService: UsersService,
|
|
|
|
|
|
) {}
|
2026-01-16 11:26:02 +08:00
|
|
|
|
|
2026-01-18 12:47:16 +08:00
|
|
|
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
2026-01-16 11:26:02 +08:00
|
|
|
|
const request = context.switchToHttp().getRequest<Request>();
|
|
|
|
|
|
|
2026-01-18 12:47:16 +08:00
|
|
|
|
// 检查是否启用 Basic Auth
|
|
|
|
|
|
const enableBasicAuth =
|
|
|
|
|
|
this.configService.get<string>('ENABLE_BASIC_AUTH') === 'true';
|
2026-01-16 11:26:02 +08:00
|
|
|
|
|
2026-01-18 15:44:37 +08:00
|
|
|
|
this.logger.log(`Basic Auth enabled: ${enableBasicAuth}`);
|
|
|
|
|
|
|
2026-01-18 12:47:16 +08:00
|
|
|
|
if (!enableBasicAuth) {
|
|
|
|
|
|
// 如果未启用 Basic Auth,允许所有访问
|
2026-01-16 11:26:02 +08:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-18 12:47:16 +08:00
|
|
|
|
// 解析 Authorization header
|
|
|
|
|
|
const authHeader = request.headers['authorization'] as string;
|
|
|
|
|
|
|
|
|
|
|
|
if (!authHeader || !authHeader.startsWith('Basic ')) {
|
2026-01-18 15:44:37 +08:00
|
|
|
|
this.logger.warn('Missing or invalid Authorization header');
|
2026-01-18 12:47:16 +08:00
|
|
|
|
throw new UnauthorizedException('Missing or invalid Authorization header');
|
2026-01-16 11:26:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-18 12:47:16 +08:00
|
|
|
|
// 解码 Basic Auth
|
|
|
|
|
|
const base64Credentials = authHeader.split(' ')[1];
|
|
|
|
|
|
const credentials = Buffer.from(base64Credentials, 'base64').toString(
|
|
|
|
|
|
'utf-8',
|
|
|
|
|
|
);
|
|
|
|
|
|
const [username, password] = credentials.split(':');
|
|
|
|
|
|
|
|
|
|
|
|
if (!username || !password) {
|
2026-01-18 15:44:37 +08:00
|
|
|
|
this.logger.warn('Invalid credentials format');
|
2026-01-18 12:47:16 +08:00
|
|
|
|
throw new UnauthorizedException('Invalid credentials format');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-18 15:44:37 +08:00
|
|
|
|
this.logger.log(`Attempting login for user: ${username}`);
|
|
|
|
|
|
|
2026-01-18 12:47:16 +08:00
|
|
|
|
// 验证用户
|
|
|
|
|
|
const user = await this.usersService.validateUser(username, password);
|
|
|
|
|
|
|
|
|
|
|
|
if (!user) {
|
2026-01-18 15:44:37 +08:00
|
|
|
|
this.logger.warn(`Login failed for user: ${username} - Invalid username or password`);
|
2026-01-18 12:47:16 +08:00
|
|
|
|
throw new UnauthorizedException('Invalid username or password');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-18 15:44:37 +08:00
|
|
|
|
this.logger.log(`User ${username} logged in successfully`);
|
|
|
|
|
|
|
2026-01-18 12:47:16 +08:00
|
|
|
|
// 将用户信息附加到请求对象
|
|
|
|
|
|
(request as any).user = user;
|
|
|
|
|
|
|
2026-01-16 11:26:02 +08:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|