bag
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
# YhCore 开发规范
|
||||
|
||||
> .NET 5.0 后端框架(参照 Java 版 bschclassmanage 迁移),仅框架无业务逻辑。
|
||||
|
||||
## 1. 解决方案结构
|
||||
|
||||
```
|
||||
YhCore.sln
|
||||
├─ src/
|
||||
│ ├─ YhCore.WebApi # 启动项:Controllers / Middleware / Filters / Attributes / Auth
|
||||
│ ├─ YhCore.Service # 业务服务层:Interfaces / Impl(不含业务时用 *Stub 占位)
|
||||
│ ├─ YhCore.Repository # 数据层:YHDbContext / IRepository<T> / Specification / DapperChannel
|
||||
│ ├─ YhCore.Entity # 数据库实体(旧 EF6 POCO 迁移而来,无导航属性)
|
||||
│ ├─ YhCore.Model # DTO / VO / Boa 平台占位模型
|
||||
│ ├─ YhCore.Common # 工具:ApiRoutes / UserContext / RedisUtil / PageUtil / ApiResult
|
||||
│ └─ YhCore.Tasks # 调度:QuartzHostedService / Jobs
|
||||
└─ lib / docker / docs / sqlscript
|
||||
```
|
||||
|
||||
**依赖方向(单向,禁止反向引用)**:WebApi → Service → Repository → Entity;WebApi → Model ← Service;Common 不依赖任何上层。
|
||||
|
||||
**底层框架(Yh.Platform.\*)**:CAS 认证、用户上下文(BoaUserContext)、应用验签(AppAuthVerifier)、用户中心(OpenApi)均由底层框架提供:
|
||||
- 引用 DLL:`Yh.Platform.Abstractions` / `Yh.Platform.AppAuth` / `Yh.Platform.Auth` / `Yh.Platform.OpenApi`(lib 目录,源码在 `E:\YHXT\net\YHBasePlatformDotnet`)
|
||||
- `Startup` 用 `services.AddYhPlatform(Configuration)` 聚合注册(= AddYhAppAuth + AddYhAuth[含 AddYhOpenApi]),管道用 `app.UseYhUserContext()` 注入用户上下文
|
||||
- 旧自研 CAS/验签/用户中心实现已退役到 `src/_legacy/`(不参与编译,仅留档备份);业务代码取当前用户用 `BoaUserContext.Get()`
|
||||
|
||||
**`/oapi` 开放渠道契约**:应用间调用渠道,**无需用户登录**,凭签名票据直接访问:
|
||||
- 票据 = 请求头 `X-App-Key` / `X-Timestamp` / `X-Signature`(`signature = Base64(HmacSHA256(METHOD + "\n" + path[?sortedQuery] + "\n" + timestamp, secret))`,详见框架仓库 `YHBasePlatformDotnet\BasePlatformDotnet\contract\sign-protocol.md`)
|
||||
- 未带票据/票据非法 → `401 {code:4,msg:"缺少签名头…"/"签名校验失败…"}`;验签通过 → 放行到业务(无用户上下文,业务只可读 `UserContextHolder.Get().AppKey` 应用身份)
|
||||
- SSO 登录保护**永不拦截** `/oapi`(SsoProtectionMiddleware 显式放行,即使 `yh:sso:urlPattern` 误配也不影响);服务端验签密钥解析链:配置内置应用(`yh:app-auth` AppKey/AppSecret)→ Redis `sign:app:{appKey}` → 本地缓存 → UserBase 兜底
|
||||
|
||||
**`/oapi` 冒烟验证方法**:本地联调/自测票据可用 `scripts/oapi-sign.js` 生成(对齐签名协议):
|
||||
- 生成票据:`node scripts/oapi-sign.js GET "/oapi/hello?a=2&b=1"` → 输出 `appKey/ts/signature` 三头
|
||||
- 直接出 curl:`node scripts/oapi-sign.js --curl POST "/oapi/xxx"` → 复制替换 `PORT` 即可
|
||||
- 密钥默认取开发联调密钥(`yh:app-auth`),生产环境用 `APP_KEY` / `APP_SECRET` 环境变量覆盖,**禁止提交真实密钥到仓库**
|
||||
- 断言基线:无票据 → 401 `{code:4}`;合法票据 → 直达业务(404/业务结果);假票据 → 401;`/api`、`/mobiapi` 无 Cookie → 302 CAS(SSO 保护不受影响)
|
||||
|
||||
## 2. 强制规范
|
||||
|
||||
| 约定 | 说明 |
|
||||
|---|---|
|
||||
| **接口路径** | 一律用 `[Route(ApiRoutes.ApiPath + "/xxx")]`,禁止硬编码 `"api/..."`;渠道前缀见 `ApiRoutes`(api/mobiapi/oapi) |
|
||||
| **接口返回结构** | 与 Java 版保持一致(裸返回),**全局 `GlobalWrapResultFilter` 自动统一包装**(ApiResult{code,msg,data});需要裸返回用 `[NoWrapResult]` 显式排除;异常由 `GlobalExceptionMiddleware` 统一转失败响应 |
|
||||
| **业务异常** | Service 层抛 `new DException(ErrorCodeUtil.From(code), "提示语")`(框架 `Yh.Platform.Abstractions`);仅提示语可用便捷构造 `new DException("提示语")`(默认 Custom=5);中间件自动转统一失败响应 |
|
||||
| **日志** | **只允许接口访问日志**(ApiAccessLogMiddleware 自动记录)。业务代码禁止调用 `ILogger` 写日志;异常摘要由接口日志统一带出 |
|
||||
| **缓存 Key** | 必须用 `RedisConstants.KeyOf(...)` 生成;过期时间用 `RedisConstants.CACHE_EXPIRE_*` |
|
||||
| **分页** | 页码从 0 开始(与 Spring Pageable 对齐);数据库分页用 `IRepository<T>.PageAsync`,内存分页用 `PageUtil` |
|
||||
| **动态条件** | 用 `Specification.True<T>().And(...).AndIf(cond, ...)` 拼装 |
|
||||
| **操作日志** | **接口级审计日志,全局自动**:`SysOperationLogFilter`(Startup 全局注册)每次 Controller 请求后落库 `sys_operation_log`(对齐 Java `SysOperationLog`,含 URI/参数/响应 GZIP/耗时/状态码/异常),无需任何标注;级别按 HTTP 方法推导(GET=QUERY/POST=ADD/PUT=EDIT/DELETE=DELETE);`LogController` 已显式排除防递归 |
|
||||
| **实体主键** | 实体无 `[Key]` 时按约定推断(Id → SerID);新增表实体建议显式标注 |
|
||||
| **数据库** | 默认 SQL Server 主库;`DatabaseProvider=MySql` 切换;**缺表自动补建**(`Database:AutoCreateMissingTables`,默认 true:启动时对比 EF 模型与数据库,缺失的表按模型自动 CREATE,幂等;已存在表的结构变更仍走 sqlscript 脚本) |
|
||||
| **数据库写操作** | 注意 `RepositoryBase` 的 Add/Update 需调用 `SaveChangesAsync()` 提交(UnitOfWork 模式) |
|
||||
|
||||
## 3. 常用命令
|
||||
|
||||
```bash
|
||||
dotnet build # 编译
|
||||
dotnet run --project src/YhCore.WebApi # 本地运行(Swagger: /swagger/index.html)
|
||||
dotnet watch run --project src/YhCore.WebApi
|
||||
```
|
||||
|
||||
## 4. 环境配置(appsettings.json 或环境变量覆盖)
|
||||
|
||||
| 配置 | 默认值 | 说明 |
|
||||
|---|---|---|
|
||||
| `DatabaseProvider` | `SqlServer` | `SqlServer` / `MySql` |
|
||||
| `Database:AutoCreateMissingTables` | `true` | 启动时自动补建 EF 模型中有而数据库缺失的表(仅 SQL Server;幂等;已存在表不触碰,结构变更仍走 sqlscript) |
|
||||
| `ConnectionStrings__SqlServer` | localhost/EduCloudDocPrint | 主库连接串(生产用环境变量,勿提交明文密码) |
|
||||
| `ConnectionStrings__Mysql` | localhost:3306 | MySQL 备用连接串 |
|
||||
| `Redis:ConnectionString` | localhost:6379,defaultDatabase=0 | Redis 连接串 |
|
||||
| `yh:auth:CookieName` | `.yh.auth` | 认证 Cookie 名 |
|
||||
| `yh:auth:CookieExpireMinutes` | `1` | 登录态固定过期(分钟),不滑动续期;票据存服务端内存(SessionTicketDataFormat),Cookie 只写 32 位 key;会话级 Cookie(IsPersistent=false),关闭浏览器即失效;**显式退出(/api/Logout)时服务端票据立即吊销**(OnSigningOut 事件,不等过期兜底) |
|
||||
| `yh:sso:Enabled` | `true` | CAS SSO 开关(拦截 urlPattern / mobiApiPattern) |
|
||||
| `yh:sso:CasServerUrlPrefix` | - | CAS 服务端地址前缀(Challenge 跳转用) |
|
||||
| `yh:app-auth:Enabled` | `true` | /oapi 应用验签开关(X-App-Key / X-Timestamp / X-Signature) |
|
||||
| `yh:open:AppKey` / `yh:open:AppSecret` | 100002 | OpenApi 调用方凭证 |
|
||||
|
||||
## 5. 待办(TODO)
|
||||
|
||||
- [x] CAS 认证:已由 `Yh.Platform.Auth`(CasScheme)接管,旧本地实现退役到 `_legacy/Auth`
|
||||
- [x] 应用签名:`AppAuthMiddleware` 已接入 `AppAuthVerifier` + `SignCanonical` 真实验签
|
||||
- [x] 用户中心:`IUserCenterService` 已替换为 `Yh.Platform.OpenApi`(`BoaUserContext.Get()` 取上下文)
|
||||
- [ ] `ILogService` 真实查询实现(替换 LogServiceStub)
|
||||
- [x] Quartz Job 按业务启用:`CleanupLogJob` 已实现(每日凌晨 3:30 删除 30 天前 `sys_operation_log`),`QuartzHostedService.InitJobs` 已注册 `cleanup-log-job`(cron `0 30 3 * * ?`)
|
||||
- [ ] 审计日志增强(`SysOperationLogFilter` 目前按 HTTP 方法推导级别,`Module/Operation` 两列恒空,可接入业务字典映射;日志查询走 `LogController` 但 `LogServiceStub` 尚未实现真实分页查询)
|
||||
- [ ] .NET 5 已 EOL:框架代码避免使用 5.0 专属 API,便于日后升 6/8
|
||||
Reference in New Issue
Block a user