一、项目名称
Admin.NET 后台管理系统(基础版)
二、项目核心定位
基于 .NET 8 + DDD 四层架构,整合前 4 周所学(仓储模式、EF Core、AutoMapper、JWT、RBAC 权限),打造可直接落地、前后端联动的标准后台管理系统基础版,覆盖企业后台核心功能,适配前端模板,可直接用于学习演示、简历项目或小型企业实际使用。
三、项目技术栈(完全贴合前 4 周学习内容)
后端技术栈(核心)
- 框架:.NET 8 Web API
- 架构:DDD 四层架构(Interface/API 层 → Application 应用层 → Domain 领域层 → Infrastructure 基础设施层)
- 数据访问:EF Core 8 + 泛型仓储模式 + 工作单元(UOW)事务
- 对象映射:AutoMapper(Profile 统一配置)
- 认证授权:JWT 无状态认证 + RBAC 基于角色的权限控制
- 密码安全:BCrypt 加盐哈希加密
- 统一规范:DTO 入参、VO 出参、统一返回格式(R<T>)、异常处理基础
前端技术栈(适配模板,简单易上手)
选用 Element Plus + Vue 3 + Vue Router 开源后台模板(无需从零开发,直接适配后端接口),核心依赖:
- 框架:Vue 3(Composition API)
- UI 组件:Element Plus(饿了么开源组件库,适配后台管理场景)
- 路由:Vue Router(动态路由渲染)
- 请求工具:Axios(统一请求拦截、Token 携带)
- 模板选型:vue-admin-template(简化版,轻量易适配,无需复杂配置)
四、详细需求(分模块,全覆盖前 4 周知识点)
总体需求
- 系统整体遵循 DDD 四层架构规范,禁止 Entity 直接暴露到前端,所有接口入参用 DTO、出参用 VO。
- 实现完整的 JWT 登录认证,未登录用户无法访问受保护接口,Token 过期 / 非法返回 401。
- 基于 RBAC 模型实现权限控制:用户→角色→菜单,不同角色看到不同的菜单和接口权限。
- 前后端联动:前端模板适配后端接口,实现动态路由、侧边栏渲染、权限控制、数据展示。
- 所有业务操作(新增 / 修改 / 删除 / 分配权限)均需事务保证,避免数据异常。
- 核心模块(用户、角色、菜单)实现完整 CRUD,符合企业后台操作规范。
模块 1:系统基础配置(支撑所有模块)
1.1 全局配置
- 后端:appsettings.json 配置 JWT(密钥、过期时间、签发人)、数据库连接字符串。
- 前端:配置后端接口基础地址、Token 存储(localStorage)、请求拦截(自动携带 Bearer Token)。
1.2 统一规范
- 后端:统一返回格式 R<T>(code:状态码、msg:提示信息、data:返回数据),成功状态码 200,失败 500/400/401。
- 前端:统一请求封装,拦截 401 状态码,自动跳转登录页;统一提示组件(成功 / 失败提示)。
模块 2:用户管理模块(Day19、Day20、Day23 核心内容)
2.1 功能需求
-
登录功能
- 前端:登录表单(账号、密码),提交后存储 Token,跳转首页;退出登录清除 Token,跳转登录页。
- 后端:接收 LoginDto(Account、Password),按账号查询用户,BCrypt 校验密码,生成 JWT Token,返回 LoginVo(Token、UserId、Account、Name)。
- 特殊校验:账号不存在 / 密码错误,统一返回 "账号或密码错误"(避免泄露敏感信息)。
-
用户 CRUD
- 新增用户:接收 UserCreateDto(Account、Password、Name、Status),Password 用 BCrypt 加密存储,校验账号唯一性,关联默认角色(普通用户)。
- 修改用户:接收 UserUpdateDto(Id、Name、Status),不允许修改账号;如需修改密码,单独提供 "重置密码" 接口,密码加密存储。
- 删除用户:删除前校验是否关联角色,关联则提示 "该用户已分配角色,无法删除";删除用户同时删除 UserRole 关联数据。
- 查询用户:支持分页查询(接收 UserPageQueryDto:页码、页大小、账号模糊查询),返回 PageVO<List<UserVO>>;支持根据 ID 查询用户详情(含关联角色列表)。
-
用户分配角色
- 前端:用户详情页,下拉选择角色(多选),提交角色 ID 列表。
- 后端:接收 AssignRoleDto(UserId、RoleIds),先删除该用户原有关联角色(UserRole),再新增关联数据,事务保证。
2.2 接口需求(RESTful 风格)
| 接口地址 | 请求方式 | 接口描述 | 权限要求 | 入参 | 出参 |
|---|---|---|---|---|---|
| /api/user/login | POST | 用户登录 | 匿名 | LoginDto | R<LoginVo> |
| /api/user/page | GET | 分页查询用户 | 需登录 | UserPageQueryDto | R<PageVO<List<UserVO>>> |
| /api/user/{id} | GET | 查询用户详情 | 需登录 | 路径参数 id | R<UserDetailVO> |
| /api/user/add | POST | 新增用户 | 需登录 | UserCreateDto | R<string> |
| /api/user/update | PUT | 修改用户 | 需登录 | UserUpdateDto | R<string> |
| /api/user/delete/{id} | DELETE | 删除用户 | 需登录 | 路径参数 id | R<string> |
| /api/user/assignRole | POST | 分配角色 | 需登录 | AssignRoleDto | R<string> |
模块 3:角色管理模块(Day25、Day26 核心内容)
3.1 功能需求
-
角色 CRUD
- 新增角色:接收 RoleCreateDto(Name、Code、Sort、Status),校验角色编码(Code)唯一性(如 admin、common)。
- 修改角色:接收 RoleUpdateDto(Id、Name、Code、Sort、Status),校验编码唯一性,不允许修改已被用户关联的角色编码。
- 删除角色:删除前校验是否关联用户,关联则提示 "该角色已分配用户,无法删除";删除角色同时删除 RoleMenu 关联数据。
- 查询角色:支持列表查询(无分页,角色数量较少),返回 List<RoleVO>;支持根据 ID 查询角色详情(含关联菜单列表)。
-
角色分配菜单
- 前端:角色详情页,树形选择菜单(多选),提交菜单 ID 列表。
- 后端:接收 AssignMenuDto(RoleId、MenuIds),先删除该角色原有关联菜单(RoleMenu),再新增关联数据,事务保证。
3.2 接口需求
| 接口地址 | 请求方式 | 接口描述 | 权限要求 | 入参 | 出参 |
|---|---|---|---|---|---|
| /api/role/list | GET | 查询所有角色 | 需登录 | 无 | R<List<RoleVO>> |
| /api/role/{id} | GET | 查询角色详情 | 需登录 | 路径参数 id | R<RoleDetailVO> |
| /api/role/add | POST | 新增角色 | 需登录 | RoleCreateDto | R<string> |
| /api/role/update | PUT | 修改角色 | 需登录 | RoleUpdateDto | R<string> |
| /api/role/delete/{id} | DELETE | 删除角色 | 需登录 | 路径参数 id | R<string> |
| /api/role/assignMenu | POST | 分配菜单 | 需登录 | AssignMenuDto | R<string> |
模块 4:菜单管理模块(Day25、Day27 核心内容)
4.1 功能需求
-
菜单 CRUD
- 新增菜单:接收 MenuCreateDto(Name、Path、Component、Permission、ParentId、MenuType、Sort、Status),MenuType 区分目录(0)、菜单(1)、按钮(2);按钮菜单需填写 Permission(如 user:add、user:delete)。
- 修改菜单:接收 MenuUpdateDto(Id、Name、Path、Component、Permission、ParentId、MenuType、Sort、Status),不允许修改已被角色关联的菜单 Permission。
- 删除菜单:删除前校验是否有子菜单,有则提示 "存在子菜单,无法删除";删除菜单同时删除 RoleMenu 关联数据。
- 查询菜单:支持全量菜单树形查询(返回菜单树,用于角色分配菜单);支持根据当前登录用户查询专属菜单树(用于前端动态路由、侧边栏渲染)。
-
菜单树形结构
- 后端:递归构建菜单树(ParentId 关联父菜单,顶级菜单 ParentId=0),返回 List<MenuVo>(含 Children 子菜单)。
- 前端:接收菜单树数据,渲染侧边栏(目录只展示,菜单可点击跳转,按钮权限用于控制页面按钮显示 / 隐藏)。
4.2 接口需求
表格
| 接口地址 | 请求方式 | 接口描述 | 权限要求 | 入参 | 出参 |
|---|---|---|---|---|---|
| /api/menu/treeList | GET | 全量菜单树 | 需登录 | 无 | R<List<MenuVo>> |
| /api/menu/userMenuTree | GET | 当前用户菜单树 | 需登录 | 无(从 Token 解析 UserId) | R<List<MenuVo>> |
| /api/menu/add | POST | 新增菜单 | 需登录 | MenuCreateDto | R<string> |
| /api/menu/update | PUT | 修改菜单 | 需登录 | MenuUpdateDto | R<string> |
| /api/menu/delete/{id} | DELETE | 删除菜单 | 需登录 | 路径参数 id | R<string> |
模块 5:前后端联动核心需求(前端模板适配)
5.1 前端模板选型与配置
选用 vue-admin-template(Vue3 + Element Plus 版本) ,地址:https://gitee.com/mirrors/vue-admin-template(简化版,无需复杂配置,直接替换接口地址即可)。
5.2 前端核心适配
-
登录页面适配
- 替换登录接口地址为
/api/user/login,接收账号密码,存储返回的 Token 到 localStorage。 - 配置请求拦截器:所有请求头携带
Authorization: Bearer ${Token},拦截 401 状态码,跳转登录页。
- 替换登录接口地址为
-
动态路由与侧边栏
- 登录成功后,调用
/api/menu/userMenuTree接口,获取当前用户菜单树。 - 根据菜单树动态生成 Vue Router 路由(目录对应父路由,菜单对应子路由,按钮不生成路由)。
- 侧边栏(Sidebar)根据菜单树自动渲染,高亮当前路由。
- 登录成功后,调用
-
权限控制
- 页面按钮权限:根据菜单树中按钮的 Permission(如 user:add),控制按钮显示 / 隐藏(如无 user:add 权限,隐藏 "新增用户" 按钮)。
- 接口权限:后端已通过 JWT 鉴权 + RBAC 权限校验,前端无权限时,接口返回 403,前端提示 "无权限访问"。
-
数据展示适配
- 用户列表页:适配
/api/user/page分页接口,实现分页、模糊查询、删除、编辑、分配角色功能。 - 角色列表页:适配
/api/role/list接口,实现角色 CRUD、分配菜单功能。 - 菜单列表页:适配
/api/menu/treeList接口,用树形组件展示菜单,实现菜单 CRUD 功能。
- 用户列表页:适配
五、项目架构详细说明(贴合前 4 周 DDD 四层架构)
后端架构目录(完整结构,可直接复制创建)
Admin.NET
├─ Admin.NET.API(Interface 接口层)
│ ├─ Controllers
│ │ ├─ UserController.cs(用户接口)
│ │ ├─ RoleController.cs(角色接口)
│ │ └─ MenuController.cs(菜单接口)
│ ├─ Program.cs(服务注册、中间件配置)
│ └─ appsettings.json(配置文件)
├─ Admin.NET.Application(应用层)
│ ├─ Dtos(入参 DTO)
│ │ ├─ UserDtos.cs(LoginDto、UserCreateDto 等)
│ │ ├─ RoleDtos.cs(RoleCreateDto、AssignMenuDto 等)
│ │ └─ MenuDtos.cs(MenuCreateDto、MenuUpdateDto 等)
│ ├─ Vos(出参 VO)
│ │ ├─ UserVo.cs、UserDetailVo.cs
│ │ ├─ RoleVo.cs、RoleDetailVo.cs
│ │ └─ MenuVo.cs(含树形 Children)
│ ├─ Services(业务服务)
│ │ ├─ IUserService.cs、UserService.cs
│ │ ├─ IRoleService.cs、RoleService.cs
│ │ └─ MenuService.cs
│ └─ AutoMapper(映射配置)
│ └─ AutoMapperProfile.cs(配置所有 DTO↔Entity、Entity↔VO 映射)
├─ Admin.NET.Domain(领域层)
│ ├─ Entities(实体)
│ │ ├─ User.cs、Role.cs、Menu.cs
│ │ └─ UserRole.cs、RoleMenu.cs(多对多关联表)
│ └─ Repositories(仓储接口)
│ ├─ IUserRepository.cs、IRoleRepository.cs、IMenuRepository.cs
│ ├─ IUserRoleRepository.cs、IRoleMenuRepository.cs
│ └─ IUnitOfWork.cs(工作单元接口)
└─ Admin.NET.Infrastructure(基础设施层)
├─ Repositories(仓储实现)
│ ├─ UserRepository.cs、RoleRepository.cs、MenuRepository.cs
│ ├─ UserRoleRepository.cs、RoleMenuRepository.cs
│ └─ UnitOfWork.cs(工作单元实现)
├─ Commons(工具类)
│ ├─ Jwt(JWT 服务)
│ │ └─ JwtService.cs
│ └─ Security(密码加密)
│ └─ BCryptUtil.cs
└─ AppDbContext.cs(EF Core 上下文,配置实体关系)
核心依赖注册(Program.cs 关键代码)
// 1. 读取配置
var jwtSection = builder.Configuration.GetSection("Jwt");
var secretKey = jwtSection["Secret"]!;
var issuer = jwtSection["Issuer"]!;
var audience = jwtSection["Audience"]!;
var expireMinutes = int.Parse(jwtSection["ExpireMinutes"]!);
// 2. 注册 JWT 生成服务(登录用)
builder.Services.AddSingleton(new JwtService(secretKey, issuer, audience, expireMinutes));
// 3. 配置 JWT 认证中间件(鉴权用)
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = issuer,
ValidAudience = audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)),
ClockSkew = TimeSpan.Zero
};
});
// 4. 启用授权
builder.Services.AddAuthorization();
// 5. 注册 AutoMapper
builder.Services.AddAutoMapper(config =>
{
config.AddMaps(typeof(AutoMapperProfile).Assembly);
});
// 6. 注册仓储、工作单元、业务服务
builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();
builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddScoped<IRoleRepository, RoleRepository>();
builder.Services.AddScoped<IMenuRepository, MenuRepository>();
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<IRoleService, RoleService>();
builder.Services.AddScoped<MenuService>();
// 7. 中间件顺序(必须按此顺序)
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
六、前端模板适配步骤(极简,直接上手)
步骤 1:下载前端模板
- 克隆模板仓库:
git clone https://gitee.com/mirrors/vue-admin-template.git(Vue3 + Element Plus 版本)。 - 进入项目目录:
cd vue-admin-template,安装依赖:npm install。
步骤 2:修改前端配置(适配后端接口)
-
打开
src/utils/request.js,修改基础接口地址:// 替换为你的后端接口地址(如:http://localhost:5000) baseURL: process.env.VUE_APP_BASE_API || 'http://localhost:5000/api', -
配置请求拦截器(已自带,无需修改),自动携带 Token:
// 请求拦截器 service.interceptors.request.use( config => { // 从 localStorage 获取 Token const token = localStorage.getItem('token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }, error => { return Promise.reject(error) } ) -
配置响应拦截器(处理 401 过期):
// 响应拦截器 service.interceptors.response.use( response => { const res = response.data // 假设后端返回 code=401 表示未登录/Token 过期 if (res.code === 401) { // 清除 Token,跳转登录页 localStorage.removeItem('token') window.location.href = '/login' } return res }, error => { return Promise.reject(error) } )
步骤 3:适配登录功能
-
打开
src/views/login/index.vue,修改登录接口请求:// 替换原登录请求,调用后端 /api/user/login 接口 const login = async () => { try { const res = await request({ url: '/user/login', method: 'post', data: { account: form.account, // 对应后端 LoginDto 的 Account password: form.password // 对应后端 LoginDto 的 Password } }) if (res.code === 200) { // 存储 Token 和用户信息 localStorage.setItem('token', res.data.token) localStorage.setItem('userInfo', JSON.stringify(res.data)) // 跳转首页 router.push('/') } else { ElMessage.error(res.msg) } } catch (error) { ElMessage.error('登录失败,请重试') } }
步骤 4:适配动态路由与侧边栏
-
打开
src/store/modules/permission.js,修改获取菜单树的接口:// 替换原接口,调用后端 /api/menu/userMenuTree 接口 const getMenuTree = async () => { const res = await request({ url: '/menu/userMenuTree', method: 'get' }) if (res.code === 200) { return res.data } return [] } -
模板已自带动态路由生成逻辑,无需额外修改,重启前端后,登录成功会自动渲染侧边栏。
步骤 5:适配核心页面(以用户列表为例)
- 打开
src/views/system/user/index.vue,修改接口请求:- 分页查询:调用
/api/user/page,传递页码、页大小、模糊查询参数。 - 新增用户:调用
/api/user/add,传递 UserCreateDto 参数。 - 修改用户:调用
/api/user/update,传递 UserUpdateDto 参数。 - 删除用户:调用
/api/user/delete/{id}。 - 分配角色:调用
/api/user/assignRole,传递 AssignRoleDto 参数。
- 分页查询:调用
七、项目测试用例(覆盖所有核心功能)
| 测试场景 | 测试步骤 | 预期结果 |
|---|---|---|
| 登录功能 | 1. 输入正确账号密码;2. 点击登录 | 登录成功,跳转首页,存储 Token |
| 未登录访问 | 直接访问 /api/user/page 接口 |
返回 401,跳转登录页 |
| 新增用户 | 1. 进入用户列表,点击新增;2. 填写信息提交 | 新增成功,数据库新增用户,密码加密存储 |
| 角色分配菜单 | 1. 进入角色详情,选择菜单;2. 提交 | 角色关联菜单成功,RoleMenu 表新增数据 |
| 动态路由 | 1. 用不同角色登录;2. 查看侧边栏 | 侧边栏只显示该角色拥有的菜单 |
| 菜单删除 | 1. 选择有子菜单的菜单;2. 点击删除 | 提示 "存在子菜单,无法删除" |
| 密码校验 | 1. 输入正确账号,错误密码;2. 点击登录 | 提示 "账号或密码错误" |
八、项目扩展建议(可选,基于前 4 周内容延伸)
- 新增全局异常处理:在 API 层添加异常拦截中间件,统一捕获异常,返回规范错误信息。
- 新增 Swagger 接口文档:配置 Swagger,自动生成接口文档,方便前后端联调。
- 按钮级权限细化:后端新增
[RequirePermission("user:add")]自定义特性,前端根据接口返回的权限标识,控制按钮显示 / 隐藏。 - JWT 双 Token 无感刷新:新增 RefreshToken,Token 过期后自动刷新,提升用户体验。
- 数据缓存:用 Redis 缓存菜单树、角色权限,减少数据库查询,提升系统性能。
九、项目意义(贴合学习与简历)
- 全覆盖前 4 周所有知识点:仓储模式、EF Core、AutoMapper、JWT、RBAC、DDD 分层,是对学习内容的完整复盘与落地。
- 符合企业后台开发标准:架构规范、安全合规、前后端联动,可直接作为简历项目,体现 .NET 初级开发的核心能力。
- 可扩展性强:基于此项目,可快速扩展部门管理、数据字典、日志管理等模块,适配更多企业需求。