基于 Nest.js 和 Angular 的竞价平台
项目总体描述
本项目是一个基于 Nest.js 和 Angular 的竞价平台,旨在提供一个完整的竞标和管理系统。
项目的主要功能包括用户注册和登录、项目创建和管理、投标管理以及用户角色管理。项目的前端使用 Angular 框架构建,后端使用 Nest.js 框架构建,数据库使用 PostgreSQL,并通过 Swagger 提供 API 文档。
项目部署在 DigitalOcean 的 Droplet 上,前端通过 Nginx 进行部署。
前端 (Angular)
↓(API 请求)
Cognito (用户认证)
↓(验证通过后请求转发)
后端 (Nest.js)
↓(数据库查询)
数据库 (PostgreSQL)
↑(数据返回)
后端 (Nest.js)
↑(处理后的响应)
前端 (Angular)
项目结构
- frontend: 包含所有前端代码,使用 Angular 框架构建。
- backend: 包含所有后端代码,使用 Nest.js 框架构建。
- .github: 包含 GitHub Actions 的配置文件,用于持续集成和部署。
后端
后端构建
后端使用 Nest.js 框架构建,提供了一个模块化、可扩展的架构。主要功能包括用户认证、项目管理、投标管理等。后端通过 TypeORM 进行数据库操作,支持多种数据库类型。
后端技术栈
- Nest.js: 用于构建高效、可扩展的 Node.js 服务器端应用程序。
- TypeORM: 用于数据库交互的 ORM 框架。
- Swagger: 用于生成 API 文档,方便开发者查看和测试 API。
后端构建步骤
- 安装依赖: 在
backend
目录下运行npm install
安装所有必要的依赖。 - 配置环境变量: 在项目根目录下创建
.env
文件,配置数据库连接信息和其他环境变量。 - 运行开发服务器: 使用
npm run start:dev
启动开发服务器,支持热重载。 - 生产构建: 使用
npm run build
进行生产环境构建,生成的文件位于dist
目录。
数据库
项目使用 PostgreSQL 作为数据库,所有的数据库操作通过 TypeORM 进行。数据库初始化脚本位于 backend/SQL/init-script.sql
,可以用于创建和初始化数据库。
后端代码结构清晰,模块化设计使得功能扩展和维护更加方便。
后端安全认证
后端的安全认证通过 AWS Cognito 实现,结合 Nest.js 的拦截器和服务,确保用户的身份验证和授权。
安全认证架构
- AWS Cognito: 用于用户注册、登录和身份验证。Cognito 提供了安全的用户池和身份池管理。
- Nest.js 拦截器: 用于拦截 HTTP 请求,验证请求头中的 JWT Token,确保用户身份的合法性。
- Service 层: 负责处理与 Cognito 的交互,以及将 Cognito 用户与数据库中的用户信息关联。
实现步骤
-
Cognito 用户池配置: 在 AWS Cognito 中创建用户池,并配置应用客户端以支持 JWT Token 的生成和验证。
-
JWT 拦截器: 在 Nest.js 中创建一个拦截器,解析请求头中的 JWT Token,验证其有效性,并将用户信息附加到请求对象中。
import { Injectable, NestInterceptor, ExecutionContext, CallHandler, UnauthorizedException } from '@nestjs/common'; import { Observable } from 'rxjs'; import { AuthService } from './auth.service'; @Injectable() export class JwtInterceptor implements NestInterceptor { constructor(private readonly authService: AuthService) {} intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const request = context.switchToHttp().getRequest(); const token = request.headers.authorization?.split(' ')[1]; if (!token) { throw new UnauthorizedException('Token not found'); } const user = this.authService.validateToken(token); if (!user) { throw new UnauthorizedException('Invalid token'); } request.user = user; return next.handle(); } }
-
用户服务: 创建一个用户服务,负责从数据库中检索用户信息,并将其与 Cognito 用户进行关联。通过 Cognito ID 作为唯一标识符,将用户信息存储在数据库中。
import { Injectable } from '@nestjs/common'; import { UsersRepository } from './users.repository'; @Injectable() export class UsersService { constructor(private readonly usersRepository: UsersRepository) {} async findOrCreateUser(cognitoId: string, email: string) { let user = await this.usersRepository.findOneByCognitoId(cognitoId); if (!user) { user = await this.usersRepository.create({ cognitoId, email }); } return user; } }
-
角色和权限管理: 在数据库中定义用户角色(如管理员、客户、投标者),并在拦截器中根据角色进行权限验证。
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; @Injectable() export class RolesGuard implements CanActivate { constructor(private reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { const roles = this.reflector.get<string[]>('roles', context.getHandler()); if (!roles) { return true; } const request = context.switchToHttp().getRequest(); const user = request.user; return roles.includes(user.role); } }
在需要权限验证的 API 上添加
@Roles('admin')
装饰器,指定需要的角色。@Post() @Roles('admin') createProject(@Body() createProjectDto: CreateProjectDto) { return this.projectsService.createProject(createProjectDto); }
通过这种方式,后端能够有效地管理用户身份和权限,确保系统的安全性和可靠性。
项目管理实现
在项目管理模块中,将展示如何通过 Controller 调用 Service,再通过 Service 与数据库交互。
Controller
在 ProjectsController
中,定义处理 HTTP 请求的路由和方法。
import { Controller, Get, Post, Body, Param, Put, Delete } from '@nestjs/common';
import { ProjectsService } from './projects.service';
import { ProjectsDto } from '../entities/DTO/projects.dto';
@Controller('projects')
export class ProjectsController {
constructor(private readonly projectsService: ProjectsService) {}
@Get()
findAll() {
return this.projectsService.findAll();
}
@Get(':id')
findOne(@Param('id') id: number) {
return this.projectsService.findOne(id);
}
@Post()
create(@Body() projectDto: ProjectsDto) {
return this.projectsService.create(projectDto);
}
@Put(':id')
update(@Param('id') id: number, @Body() projectDto: ProjectsDto) {
return this.projectsService.update(id, projectDto);
}
@Delete(':id')
delete(@Param('id') id: number) {
return this.projectsService.delete(id);
}
}
Service
ProjectsService
负责业务逻辑处理,并与数据库进行交互。
import { Injectable } from '@nestjs/common';
import { DataSource } from 'typeorm';
im