Commit 0281d6ed5b5d5190d416b724095a7b24e81bb9b2
1 parent
1ad70c5f
feat(usr): V2 种子超管 + USR 权限分类 REQ-USR-001
- V2 migration 写入 4 个 USR 权限分类 + admin 超管(BCrypt $2y$10$ 密码 'admin')+ admin × 4 授权 - docs/03 末尾追加「种子数据 (V2 migration)」小节同步 SSoT - application.yml JDBC URL 加 tinyInt1isBit=false 避免 tinyint(1) 误判为 Boolean
Showing
4 changed files
with
86 additions
and
1 deletions
backend/src/main/resources/application.yml
| ... | ... | @@ -6,7 +6,7 @@ spring: |
| 6 | 6 | config: |
| 7 | 7 | import: optional:file:../.env.local[.properties] |
| 8 | 8 | datasource: |
| 9 | - url: jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_SCHEMA}?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false | |
| 9 | + url: jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_SCHEMA}?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false&tinyInt1isBit=false | |
| 10 | 10 | username: ${DB_USER} |
| 11 | 11 | password: ${DB_PASSWORD} |
| 12 | 12 | driver-class-name: com.mysql.cj.jdbc.Driver | ... | ... |
backend/src/test/java/com/xly/test4/ApplicationContextIT.java
| 1 | 1 | package com.xly.test4; |
| 2 | 2 | |
| 3 | +import java.util.Map; | |
| 4 | + | |
| 3 | 5 | import org.junit.jupiter.api.Test; |
| 4 | 6 | import org.springframework.beans.factory.annotation.Autowired; |
| 5 | 7 | import org.springframework.boot.test.context.SpringBootTest; |
| 6 | 8 | import org.springframework.context.ApplicationContext; |
| 9 | +import org.springframework.jdbc.core.JdbcTemplate; | |
| 7 | 10 | |
| 8 | 11 | import static org.assertj.core.api.Assertions.assertThat; |
| 9 | 12 | |
| ... | ... | @@ -13,9 +16,34 @@ class ApplicationContextIT { |
| 13 | 16 | @Autowired |
| 14 | 17 | private ApplicationContext context; |
| 15 | 18 | |
| 19 | + @Autowired | |
| 20 | + private JdbcTemplate jdbcTemplate; | |
| 21 | + | |
| 16 | 22 | @Test |
| 17 | 23 | void contextLoads() { |
| 18 | 24 | assertThat(context).isNotNull(); |
| 19 | 25 | assertThat(context.getBean(Application.class)).isNotNull(); |
| 20 | 26 | } |
| 27 | + | |
| 28 | + @Test | |
| 29 | + void flywayMigrationsApplied_seedDataPresent() { | |
| 30 | + Integer permCount = jdbcTemplate.queryForObject( | |
| 31 | + "SELECT COUNT(*) FROM tPermission WHERE sCategory IN " | |
| 32 | + + "('usr:user:create','usr:user:update','usr:user:list','usr:user:assign-role')", | |
| 33 | + Integer.class); | |
| 34 | + assertThat(permCount).isEqualTo(4); | |
| 35 | + | |
| 36 | + Map<String, Object> admin = jdbcTemplate.queryForMap( | |
| 37 | + "SELECT sUserType, sBrandsId, sSubsidiaryId, iIsDisabled FROM tUser WHERE sUserName = 'admin'"); | |
| 38 | + assertThat(admin.get("sUserType")).isEqualTo("ADMIN"); | |
| 39 | + assertThat(admin.get("sBrandsId")).isEqualTo("BR-DEFAULT"); | |
| 40 | + assertThat(admin.get("sSubsidiaryId")).isEqualTo("SUB-DEFAULT"); | |
| 41 | + assertThat(((Number) admin.get("iIsDisabled")).intValue()).isEqualTo(0); | |
| 42 | + | |
| 43 | + Integer authCount = jdbcTemplate.queryForObject( | |
| 44 | + "SELECT COUNT(*) FROM tUserPermission WHERE iUserId = " | |
| 45 | + + "(SELECT iIncrement FROM tUser WHERE sUserName = 'admin')", | |
| 46 | + Integer.class); | |
| 47 | + assertThat(authCount).isEqualTo(4); | |
| 48 | + } | |
| 21 | 49 | } | ... | ... |
docs/03-数据库设计文档.md
| ... | ... | @@ -229,3 +229,28 @@ tUser ──────────────────────── |
| 229 | 229 | - 字典表,提供 REQ-USR-004 登录页「版本」下拉数据。 |
| 230 | 230 | - 不与 `tUser` 建外键:账号可在多公司 / 多版本之间复用;登录时仅用作上下文选择,由应用层校验"用户是否被允许进入该公司版本"。 |
| 231 | 231 | - 当 `sEdition` 的取值集合稳定后,可改为受控字典并迁移到 `tDictionary` 类公共字典表;当前阶段独立维护。 |
| 232 | + | |
| 233 | +--- | |
| 234 | + | |
| 235 | +## 种子数据(V2 migration) | |
| 236 | + | |
| 237 | +由 `sql/migrations/V2__seed_admin_and_permissions.sql` 写入,REQ-USR-001 配套。 | |
| 238 | + | |
| 239 | +### `tPermission` | |
| 240 | + | |
| 241 | +| sCategory | sCategoryName | 用途 | | |
| 242 | +|---|---|---| | |
| 243 | +| `usr:user:create` | 新增用户 | REQ-USR-001 接口 `@PreAuthorize` | | |
| 244 | +| `usr:user:update` | 修改用户 | REQ-USR-002 接口 `@PreAuthorize` | | |
| 245 | +| `usr:user:list` | 查询用户 | REQ-USR-003 接口 `@PreAuthorize` | | |
| 246 | +| `usr:user:assign-role` | 分配用户角色 | REQ-USR-002 修改 `userType` 子权限 | | |
| 247 | + | |
| 248 | +### `tUser` — 超级管理员 | |
| 249 | + | |
| 250 | +| sUserCode | sUserName | sUserType | sLanguage | sBrandsId | sSubsidiaryId | 明文密码 | | |
| 251 | +|---|---|---|---|---|---|---| | |
| 252 | +| ADMIN001 | admin | ADMIN | zh-CN | BR-DEFAULT | SUB-DEFAULT | `admin`(BCrypt $2y$10$ 哈希存入) | | |
| 253 | + | |
| 254 | +### `tUserPermission` | |
| 255 | + | |
| 256 | +admin × 上述 4 个权限分类,全部授权(`sGrantedBy='system'`)。 | ... | ... |
sql/migrations/V2__seed_admin_and_permissions.sql
0 → 100644
| 1 | +-- V2__seed_admin_and_permissions.sql | |
| 2 | +-- REQ-USR-001 配套种子:USR 模块权限分类 + 超级管理员账号 | |
| 3 | +-- | |
| 4 | +-- 来源:docs/superpowers/specs/2026-05-13-REQ-USR-001.md § 附带基础设施 / Migration | |
| 5 | +-- 密码哈希算法:BCrypt($2y$10$,等价于 $2a$10$,Spring Security BCryptPasswordEncoder 兼容) | |
| 6 | +-- 明文密码:admin(仅本地开发/测试用,生产环境 admin 账号上线后必须立即改密) | |
| 7 | + | |
| 8 | +-- 种子权限分类(覆盖 USR 模块全部 REQ 所需) | |
| 9 | +INSERT INTO tPermission (sCategory, sCategoryName, sDescription, iIsDisabled) | |
| 10 | +VALUES | |
| 11 | + ('usr:user:create', '新增用户', 'REQ-USR-001 增加用户', 0), | |
| 12 | + ('usr:user:update', '修改用户', 'REQ-USR-002 修改用户', 0), | |
| 13 | + ('usr:user:list', '查询用户', 'REQ-USR-003 查询用户', 0), | |
| 14 | + ('usr:user:assign-role', '分配用户角色', '修改用户类型 NORMAL/ADMIN 用', 0); | |
| 15 | + | |
| 16 | +-- 种子超级管理员 | |
| 17 | +INSERT INTO tUser | |
| 18 | + (sUserCode, sUserName, iEmployeeId, sUserType, sLanguage, iCanEditDoc, | |
| 19 | + sPasswordHash, iIsDisabled, iLoginFailCount, | |
| 20 | + sBrandsId, sSubsidiaryId, sCreatedBy) | |
| 21 | +VALUES | |
| 22 | + ('ADMIN001', 'admin', NULL, 'ADMIN', 'zh-CN', 1, | |
| 23 | + '$2y$10$Diskv9jfPWYxJGof9IazgeKj2CFCztxuxH0WQ1TDJRwlizKXi1h.2', 0, 0, | |
| 24 | + 'BR-DEFAULT', 'SUB-DEFAULT', 'system'); | |
| 25 | + | |
| 26 | +-- 给 admin 授权全部 4 个权限分类 | |
| 27 | +INSERT INTO tUserPermission (iUserId, iPermissionId, sGrantedBy, sBrandsId, sSubsidiaryId) | |
| 28 | +SELECT u.iIncrement, p.iIncrement, 'system', 'BR-DEFAULT', 'SUB-DEFAULT' | |
| 29 | +FROM tUser u | |
| 30 | +CROSS JOIN tPermission p | |
| 31 | +WHERE u.sUserName = 'admin' | |
| 32 | + AND p.sCategory IN ('usr:user:create','usr:user:update','usr:user:list','usr:user:assign-role'); | ... | ... |