---
description: 后端安全认证和数据保护
globs: ["**/server/**/*", "**/*.controller.ts", "**/*.service.ts", "**/*.guard.ts"]
alwaysApply: false
---

# 后端安全规范

## 🔐 JWT 认证授权

### JWT 服务实现
```typescript
// services/auth.service.ts
import { JwtService } from '@nestjs/jwt';
import { Injectable, UnauthorizedException } from '@nestjs/common';

@Injectable()
export class AuthService {
  constructor(private jwtService: JwtService) {}
  
  // ✅ 生成 JWT Token
  async generateToken(payload: any): Promise<string> {
    return this.jwtService.sign(payload, {
      expiresIn: '24h',
      secret: process.env.JWT_SECRET,
    });
  }
  
  // ✅ 验证 JWT Token
  async verifyToken(token: string): Promise<any> {
    try {
      return this.jwtService.verify(token, {
        secret: process.env.JWT_SECRET,
      });
    } catch (error) {
      throw new UnauthorizedException('无效的访问令牌');
    }
  }
  
  // ✅ 刷新 Token
  async refreshToken(refreshToken: string): Promise<string> {
    const payload = await this.verifyToken(refreshToken);
    return this.generateToken({ 
      userId: payload.userId, 
      role: payload.role 
    });
  }
}

// guards/jwt-auth.guard.ts
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {
  canActivate(context: ExecutionContext): boolean {
    return super.canActivate(context) as boolean;
  }
  
  handleRequest(err: any, user: any, info: any) {
    if (err || !user) {
      throw err || new UnauthorizedException('认证失败');
    }
    return user;
  }
}
```

### 权限控制
```typescript
// decorators/roles.decorator.ts
import { SetMetadata } from '@nestjs/common';

export const Roles = (...roles: string[]) => SetMetadata('roles', roles);

// guards/roles.guard.ts
@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const requiredRoles = this.reflector.getAllAndOverride<string[]>('roles', [
      context.getHandler(),
      context.getClass(),
    ]);
    
    if (!requiredRoles) {
      return true;
    }
    
    const { user } = context.switchToHttp().getRequest();
    return requiredRoles.some((role) => user.role?.includes(role));
  }
}

// controllers/user.controller.ts
@Controller('users')
@UseGuards(JwtAuthGuard, RolesGuard)
export class UserController {
  @Get('admin')
  @Roles('admin')
  getAdminData() {
    return { message: '管理员专用数据' };
  }
  
  @Get('profile')
  getProfile(@Request() req) {
    return req.user;
  }
}
```

## 🔍 输入验证

### DTO 验证
```typescript
// dto/create-user.dto.ts
import { IsEmail, IsString, MinLength, IsOptional, IsEnum } from 'class-validator';
import { Transform } from 'class-transformer';

export class CreateUserDto {
  @IsEmail()
  @Transform(({ value }) => value.toLowerCase().trim())
  email: string;

  @IsString()
  @MinLength(8)
  password: string;

  @IsString()
  @IsOptional()
  firstName?: string;

  @IsString()
  @IsOptional()
  lastName?: string;

  @IsEnum(['user', 'admin'])
  role: 'user' | 'admin';
}

// main.ts
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  
  app.useGlobalPipes(new ValidationPipe({
    whitelist: true,           // 移除未定义的属性
    forbidNonWhitelisted: true, // 禁止未定义的属性
    transform: true,            // 自动类型转换
    transformOptions: {
      enableImplicitConversion: true,
    },
  }));
  
  await app.listen(3000);
}
```

## 🔒 密码安全

### 密码处理服务
```typescript
// services/password.service.ts
import * as bcrypt from 'bcrypt';

@Injectable()
export class PasswordService {
  private readonly saltRounds = 12;
  
  // ✅ 密码哈希
  async hashPassword(password: string): Promise<string> {
    return bcrypt.hash(password, this.saltRounds);
  }
  
  // ✅ 密码验证
  async verifyPassword(password: string, hashedPassword: string): Promise<boolean> {
    return bcrypt.compare(password, hashedPassword);
  }
  
  // ✅ 密码强度验证
  validatePasswordStrength(password: string): boolean {
    const minLength = 8;
    const hasUpperCase = /[A-Z]/.test(password);
    const hasLowerCase = /[a-z]/.test(password);
    const hasNumbers = /\d/.test(password);
    const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password);
    
    return password.length >= minLength && 
           hasUpperCase && 
           hasLowerCase && 
           hasNumbers && 
           hasSpecialChar;
  }
}
```

## 🚨 全局异常处理

### 异常过滤器
```typescript
// filters/global-exception.filter.ts
import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';
import { Request, Response } from 'express';

@Catch()
export class GlobalExceptionFilter implements ExceptionFilter {
  catch(exception: unknown, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    
    let status = HttpStatus.INTERNAL_SERVER_ERROR;
    let message = '内部服务器错误';
    
    if (exception instanceof HttpException) {
      status = exception.getStatus();
      message = exception.message;
    }
    
    // ✅ 记录错误日志（不暴露敏感信息）
    console.error(`[${new Date().toISOString()}] ${request.method} ${request.url}`, {
      status,
      message,
      userAgent: request.get('User-Agent'),
      ip: request.ip,
    });
    
    // ✅ 返回安全的错误响应
    response.status(status).json({
      statusCode: status,
      message: message,
      timestamp: new Date().toISOString(),
      path: request.url,
    });
  }
}
```

## 🗄️ 数据库安全

### SQL 注入防护
```typescript
// repositories/user.repository.ts
@Injectable()
export class UserRepository {
  constructor(
    @InjectRepository(User)
    private readonly repository: Repository<User>,
  ) {}
  
  // ✅ 安全的查询方法
  async findByEmail(email: string): Promise<User | null> {
    return this.repository.findOne({
      where: { email }, // TypeORM 自动参数化
    });
  }
  
  // ✅ 使用 QueryBuilder 进行复杂查询
  async findUsersWithRole(role: string, limit: number = 10): Promise<User[]> {
    return this.repository
      .createQueryBuilder('user')
      .where('user.role = :role', { role })
      .limit(limit)
      .getMany();
  }
  
  // ❌ 避免字符串拼接查询
  // async findUserUnsafe(email: string): Promise<User | null> {
  //   return this.repository.query(`SELECT * FROM users WHERE email = '${email}'`);
  // }
}
```

## 📊 安全监控

### 安全日志记录
```typescript
// services/security-logger.service.ts
@Injectable()
export class SecurityLoggerService {
  private readonly logger = new Logger(SecurityLoggerService.name);
  
  // ✅ 登录尝试记录
  logLoginAttempt(email: string, success: boolean, ip: string, userAgent: string) {
    this.logger.log({
      event: 'LOGIN_ATTEMPT',
      email: this.maskEmail(email),
      success,
      ip,
      userAgent,
      timestamp: new Date().toISOString(),
    });
  }
  
  // ✅ 权限变更记录
  logPermissionChange(userId: string, oldRole: string, newRole: string, adminId: string) {
    this.logger.log({
      event: 'PERMISSION_CHANGE',
      userId,
      oldRole,
      newRole,
      adminId,
      timestamp: new Date().toISOString(),
    });
  }
  
  // ✅ 敏感操作记录
  logSensitiveOperation(operation: string, userId: string, details: any) {
    this.logger.log({
      event: 'SENSITIVE_OPERATION',
      operation,
      userId,
      details: this.sanitizeLogData(details),
      timestamp: new Date().toISOString(),
    });
  }
  
  private sanitizeLogData(data: any): any {
    // 移除敏感信息
    const { password, token, secret, ...safeData } = data;
    return safeData;
  }
  
  private maskEmail(email: string): string {
    const [localPart, domain] = email.split('@');
    const maskedLocal = localPart.length > 2 
      ? localPart.substring(0, 2) + '*'.repeat(localPart.length - 2)
      : localPart;
    return `${maskedLocal}@${domain}`;
  }
}
```

## 🎯 后端安全最佳实践

### 必需配置项
- ✅ 使用 JWT 实现认证和授权
- ✅ 使用 ValidationPipe 验证输入数据
- ✅ 实现全局异常过滤器统一处理错误
- ✅ 使用密码哈希和盐值
- ✅ 实施安全日志记录

### 参考文件
- `services/auth.service.ts` - 认证服务
- `guards/jwt-auth.guard.ts` - JWT 守卫
- `dto/create-user.dto.ts` - 数据传输对象
- `services/password.service.ts` - 密码服务
- `filters/global-exception.filter.ts` - 全局异常过滤器