permserver_test.go 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443
  1. package server
  2. import (
  3. "context"
  4. "database/sql"
  5. "fmt"
  6. "testing"
  7. "time"
  8. authHelper "perms-system-server/internal/logic/auth"
  9. deptModel "perms-system-server/internal/model/dept"
  10. permModel "perms-system-server/internal/model/perm"
  11. productModel "perms-system-server/internal/model/product"
  12. memberModel "perms-system-server/internal/model/productmember"
  13. roleModel "perms-system-server/internal/model/role"
  14. rolePermModel "perms-system-server/internal/model/roleperm"
  15. userModel "perms-system-server/internal/model/user"
  16. userPermModel "perms-system-server/internal/model/userperm"
  17. userRoleModel "perms-system-server/internal/model/userrole"
  18. "perms-system-server/internal/svc"
  19. "perms-system-server/internal/testutil"
  20. "perms-system-server/pb"
  21. "github.com/golang-jwt/jwt/v4"
  22. "github.com/stretchr/testify/assert"
  23. "github.com/stretchr/testify/require"
  24. "golang.org/x/crypto/bcrypt"
  25. "google.golang.org/grpc/codes"
  26. "google.golang.org/grpc/status"
  27. )
  28. func bcryptHash(t *testing.T, plaintext string) string {
  29. t.Helper()
  30. h, err := bcrypt.GenerateFromPassword([]byte(plaintext), bcrypt.MinCost)
  31. require.NoError(t, err)
  32. return string(h)
  33. }
  34. // ---------- SyncPermissions ----------
  35. // TC-0230: 正常同步
  36. func TestSyncPermissions_Normal(t *testing.T) {
  37. ctx := context.Background()
  38. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  39. conn := testutil.GetTestSqlConn()
  40. now := time.Now().Unix()
  41. uid := testutil.UniqueId()
  42. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  43. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: bcryptHash(t, "secret1"),
  44. Status: 1, CreateTime: now, UpdateTime: now,
  45. })
  46. require.NoError(t, err)
  47. pId, _ := pRes.LastInsertId()
  48. t.Cleanup(func() {
  49. testutil.CleanTableByField(ctx, conn, "`sys_perm`", "productCode", uid)
  50. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  51. })
  52. srv := NewPermServer(svcCtx)
  53. resp, err := srv.SyncPermissions(ctx, &pb.SyncPermissionsReq{
  54. AppKey: uid,
  55. AppSecret: "secret1",
  56. Perms: []*pb.PermItem{
  57. {Code: "perm_a", Name: "Perm A", Remark: "remark_a"},
  58. {Code: "perm_b", Name: "Perm B", Remark: "remark_b"},
  59. },
  60. })
  61. require.NoError(t, err)
  62. assert.Equal(t, int64(2), resp.Added)
  63. assert.Equal(t, int64(0), resp.Updated)
  64. assert.Equal(t, int64(0), resp.Disabled)
  65. resp2, err := srv.SyncPermissions(ctx, &pb.SyncPermissionsReq{
  66. AppKey: uid,
  67. AppSecret: "secret1",
  68. Perms: []*pb.PermItem{
  69. {Code: "perm_a", Name: "Perm A Updated", Remark: "remark_a"},
  70. },
  71. })
  72. require.NoError(t, err)
  73. assert.Equal(t, int64(0), resp2.Added)
  74. assert.Equal(t, int64(1), resp2.Updated)
  75. assert.Equal(t, int64(1), resp2.Disabled)
  76. }
  77. // TC-0231: appKey无效
  78. func TestSyncPermissions_InvalidAppKey(t *testing.T) {
  79. ctx := context.Background()
  80. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  81. srv := NewPermServer(svcCtx)
  82. _, err := srv.SyncPermissions(ctx, &pb.SyncPermissionsReq{
  83. AppKey: "nonexistent_key",
  84. AppSecret: "any",
  85. Perms: []*pb.PermItem{{Code: "c", Name: "n"}},
  86. })
  87. require.Error(t, err)
  88. assert.Equal(t, codes.Unauthenticated, status.Code(err))
  89. assert.Equal(t, "无效的appKey", status.Convert(err).Message())
  90. }
  91. // TC-0232: appSecret错误
  92. func TestSyncPermissions_WrongAppSecret(t *testing.T) {
  93. ctx := context.Background()
  94. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  95. conn := testutil.GetTestSqlConn()
  96. now := time.Now().Unix()
  97. uid := testutil.UniqueId()
  98. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  99. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: bcryptHash(t, "real_secret"),
  100. Status: 1, CreateTime: now, UpdateTime: now,
  101. })
  102. require.NoError(t, err)
  103. pId, _ := pRes.LastInsertId()
  104. t.Cleanup(func() {
  105. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  106. })
  107. srv := NewPermServer(svcCtx)
  108. _, err = srv.SyncPermissions(ctx, &pb.SyncPermissionsReq{
  109. AppKey: uid,
  110. AppSecret: "wrong_secret",
  111. Perms: []*pb.PermItem{{Code: "c", Name: "n"}},
  112. })
  113. require.Error(t, err)
  114. assert.Equal(t, codes.Unauthenticated, status.Code(err))
  115. assert.Equal(t, "appSecret验证失败", status.Convert(err).Message())
  116. }
  117. // TC-0233: 产品已禁用
  118. func TestSyncPermissions_ProductDisabled(t *testing.T) {
  119. ctx := context.Background()
  120. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  121. conn := testutil.GetTestSqlConn()
  122. now := time.Now().Unix()
  123. uid := testutil.UniqueId()
  124. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  125. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: bcryptHash(t, "secret1"),
  126. Status: 2, CreateTime: now, UpdateTime: now,
  127. })
  128. require.NoError(t, err)
  129. pId, _ := pRes.LastInsertId()
  130. t.Cleanup(func() {
  131. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  132. })
  133. srv := NewPermServer(svcCtx)
  134. _, err = srv.SyncPermissions(ctx, &pb.SyncPermissionsReq{
  135. AppKey: uid,
  136. AppSecret: "secret1",
  137. Perms: []*pb.PermItem{{Code: "c", Name: "n"}},
  138. })
  139. require.Error(t, err)
  140. assert.Equal(t, codes.PermissionDenied, status.Code(err))
  141. assert.Equal(t, "产品已被禁用", status.Convert(err).Message())
  142. }
  143. // ---------- Login ----------
  144. // TC-0235: 正常登录(普通用户+productCode)
  145. func TestLogin_Normal(t *testing.T) {
  146. ctx := context.Background()
  147. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  148. conn := testutil.GetTestSqlConn()
  149. now := time.Now().Unix()
  150. uid := testutil.UniqueId()
  151. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  152. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  153. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  154. Status: 1, CreateTime: now, UpdateTime: now,
  155. })
  156. require.NoError(t, err)
  157. uId, _ := uRes.LastInsertId()
  158. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  159. Code: uid, Name: "test_prod", AppKey: uid + "_k", AppSecret: "s1",
  160. Status: 1, CreateTime: now, UpdateTime: now,
  161. })
  162. require.NoError(t, err)
  163. pId, _ := pRes.LastInsertId()
  164. pmRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  165. ProductCode: uid, UserId: uId, MemberType: "MEMBER", Status: 1,
  166. CreateTime: now, UpdateTime: now,
  167. })
  168. require.NoError(t, err)
  169. pmId, _ := pmRes.LastInsertId()
  170. t.Cleanup(func() {
  171. testutil.CleanTable(ctx, conn, "`sys_product_member`", pmId)
  172. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  173. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  174. })
  175. srv := NewPermServer(svcCtx)
  176. resp, err := srv.Login(ctx, &pb.LoginReq{
  177. Username: uid,
  178. Password: "pass123",
  179. ProductCode: uid,
  180. })
  181. require.NoError(t, err)
  182. assert.NotEmpty(t, resp.AccessToken)
  183. assert.NotEmpty(t, resp.RefreshToken)
  184. assert.True(t, resp.Expires > time.Now().Unix(), "expires应为未来的unix时间戳")
  185. assert.Equal(t, uId, resp.UserId)
  186. assert.Equal(t, uid, resp.Username)
  187. // BUG-01: proto定义了nickname字段,实现应返回用户昵称
  188. assert.Equal(t, "nick", resp.Nickname, "BUG-01: LoginResp.Nickname 应返回用户昵称而非空字符串")
  189. }
  190. // TC-0236: 用户不存在
  191. func TestLogin_UserNotFound(t *testing.T) {
  192. ctx := context.Background()
  193. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  194. srv := NewPermServer(svcCtx)
  195. _, err := srv.Login(ctx, &pb.LoginReq{
  196. Username: "nonexistent_user_xyz",
  197. Password: "any",
  198. ProductCode: "any_product",
  199. })
  200. require.Error(t, err)
  201. assert.Equal(t, codes.Unauthenticated, status.Code(err))
  202. assert.Equal(t, "用户名或密码错误", status.Convert(err).Message())
  203. }
  204. // TC-0237: 密码错误
  205. func TestLogin_WrongPassword(t *testing.T) {
  206. ctx := context.Background()
  207. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  208. conn := testutil.GetTestSqlConn()
  209. now := time.Now().Unix()
  210. uid := testutil.UniqueId()
  211. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  212. Username: uid, Password: testutil.HashPassword("correct_pass"), Nickname: "nick",
  213. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  214. Status: 1, CreateTime: now, UpdateTime: now,
  215. })
  216. require.NoError(t, err)
  217. uId, _ := uRes.LastInsertId()
  218. t.Cleanup(func() {
  219. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  220. })
  221. srv := NewPermServer(svcCtx)
  222. _, err = srv.Login(ctx, &pb.LoginReq{
  223. Username: uid,
  224. Password: "wrong_pass",
  225. ProductCode: "any_product",
  226. })
  227. require.Error(t, err)
  228. assert.Equal(t, codes.Unauthenticated, status.Code(err))
  229. assert.Equal(t, "用户名或密码错误", status.Convert(err).Message())
  230. }
  231. // TC-0238: 账号冻结
  232. func TestLogin_AccountFrozen(t *testing.T) {
  233. ctx := context.Background()
  234. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  235. conn := testutil.GetTestSqlConn()
  236. now := time.Now().Unix()
  237. uid := testutil.UniqueId()
  238. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  239. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  240. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  241. Status: 2, CreateTime: now, UpdateTime: now,
  242. })
  243. require.NoError(t, err)
  244. uId, _ := uRes.LastInsertId()
  245. t.Cleanup(func() {
  246. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  247. })
  248. srv := NewPermServer(svcCtx)
  249. _, err = srv.Login(ctx, &pb.LoginReq{
  250. Username: uid,
  251. Password: "pass123",
  252. ProductCode: "any_product",
  253. })
  254. require.Error(t, err)
  255. assert.Equal(t, codes.PermissionDenied, status.Code(err))
  256. assert.Equal(t, "账号已被冻结", status.Convert(err).Message())
  257. }
  258. // TC-0239: 超管被拒绝
  259. func TestLogin_SuperAdminRejected(t *testing.T) {
  260. ctx := context.Background()
  261. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  262. conn := testutil.GetTestSqlConn()
  263. now := time.Now().Unix()
  264. uid := testutil.UniqueId()
  265. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  266. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "sa",
  267. Avatar: sql.NullString{}, IsSuperAdmin: 1, MustChangePassword: 2,
  268. Status: 1, CreateTime: now, UpdateTime: now,
  269. })
  270. require.NoError(t, err)
  271. uId, _ := uRes.LastInsertId()
  272. t.Cleanup(func() {
  273. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  274. })
  275. srv := NewPermServer(svcCtx)
  276. _, err = srv.Login(ctx, &pb.LoginReq{
  277. Username: uid,
  278. Password: "pass123",
  279. ProductCode: "any_product",
  280. })
  281. require.Error(t, err)
  282. assert.Equal(t, codes.PermissionDenied, status.Code(err))
  283. assert.Equal(t, "超级管理员不允许通过产品端登录,请使用管理后台", status.Convert(err).Message())
  284. }
  285. // TC-0240: 普通用户+productCode
  286. func TestLogin_NormalUserWithProductCode(t *testing.T) {
  287. ctx := context.Background()
  288. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  289. conn := testutil.GetTestSqlConn()
  290. now := time.Now().Unix()
  291. uid := testutil.UniqueId()
  292. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  293. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  294. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  295. Status: 1, CreateTime: now, UpdateTime: now,
  296. })
  297. require.NoError(t, err)
  298. uId, _ := uRes.LastInsertId()
  299. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  300. Code: uid, Name: "test_prod", AppKey: uid + "_k", AppSecret: "s1",
  301. Status: 1, CreateTime: now, UpdateTime: now,
  302. })
  303. require.NoError(t, err)
  304. pId, _ := pRes.LastInsertId()
  305. mbrRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  306. ProductCode: uid, UserId: uId, MemberType: "MEMBER",
  307. Status: 1, CreateTime: now, UpdateTime: now,
  308. })
  309. require.NoError(t, err)
  310. mbrId, _ := mbrRes.LastInsertId()
  311. roleRes, err := svcCtx.SysRoleModel.Insert(ctx, &roleModel.SysRole{
  312. ProductCode: uid, Name: uid + "_role", Status: 1, PermsLevel: 1,
  313. CreateTime: now, UpdateTime: now,
  314. })
  315. require.NoError(t, err)
  316. roleId, _ := roleRes.LastInsertId()
  317. pm1Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  318. ProductCode: uid, Name: "p1", Code: uid + "_c1",
  319. Status: 1, CreateTime: now, UpdateTime: now,
  320. })
  321. require.NoError(t, err)
  322. pm1Id, _ := pm1Res.LastInsertId()
  323. urRes, err := svcCtx.SysUserRoleModel.Insert(ctx, &userRoleModel.SysUserRole{
  324. UserId: uId, RoleId: roleId, CreateTime: now, UpdateTime: now,
  325. })
  326. require.NoError(t, err)
  327. urId, _ := urRes.LastInsertId()
  328. rpRes, err := svcCtx.SysRolePermModel.Insert(ctx, &rolePermModel.SysRolePerm{
  329. RoleId: roleId, PermId: pm1Id, CreateTime: now, UpdateTime: now,
  330. })
  331. require.NoError(t, err)
  332. rpId, _ := rpRes.LastInsertId()
  333. t.Cleanup(func() {
  334. testutil.CleanTable(ctx, conn, "`sys_role_perm`", rpId)
  335. testutil.CleanTable(ctx, conn, "`sys_user_role`", urId)
  336. testutil.CleanTable(ctx, conn, "`sys_perm`", pm1Id)
  337. testutil.CleanTable(ctx, conn, "`sys_role`", roleId)
  338. testutil.CleanTable(ctx, conn, "`sys_product_member`", mbrId)
  339. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  340. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  341. })
  342. srv := NewPermServer(svcCtx)
  343. resp, err := srv.Login(ctx, &pb.LoginReq{
  344. Username: uid,
  345. Password: "pass123",
  346. ProductCode: uid,
  347. })
  348. require.NoError(t, err)
  349. assert.Equal(t, "MEMBER", resp.MemberType)
  350. assert.Contains(t, resp.Perms, uid+"_c1")
  351. assert.NotEmpty(t, resp.AccessToken)
  352. assert.NotEmpty(t, resp.RefreshToken)
  353. }
  354. // TC-0242: productCode为空
  355. func TestLogin_EmptyProductCode(t *testing.T) {
  356. ctx := context.Background()
  357. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  358. srv := NewPermServer(svcCtx)
  359. _, err := srv.Login(ctx, &pb.LoginReq{
  360. Username: "anyuser",
  361. Password: "anypass",
  362. ProductCode: "",
  363. })
  364. require.Error(t, err)
  365. assert.Equal(t, codes.InvalidArgument, status.Code(err))
  366. assert.Equal(t, "productCode不能为空", status.Convert(err).Message())
  367. }
  368. // ---------- RefreshToken ----------
  369. // TC-0243: 正常刷新(refreshToken原样返回,不重新生成)
  370. func TestRefreshToken_Normal(t *testing.T) {
  371. ctx := context.Background()
  372. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  373. conn := testutil.GetTestSqlConn()
  374. now := time.Now().Unix()
  375. uid := testutil.UniqueId()
  376. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  377. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  378. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  379. Status: 1, CreateTime: now, UpdateTime: now,
  380. })
  381. require.NoError(t, err)
  382. uId, _ := uRes.LastInsertId()
  383. t.Cleanup(func() {
  384. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  385. })
  386. cfg := testutil.GetTestConfig()
  387. refreshToken, err := authHelper.GenerateRefreshToken(cfg.Auth.RefreshSecret, cfg.Auth.RefreshExpire, uId, "", 0)
  388. require.NoError(t, err)
  389. srv := NewPermServer(svcCtx)
  390. resp, err := srv.RefreshToken(ctx, &pb.RefreshTokenReq{
  391. RefreshToken: refreshToken,
  392. })
  393. require.NoError(t, err)
  394. assert.NotEmpty(t, resp.AccessToken)
  395. assert.NotEqual(t, refreshToken, resp.RefreshToken, "M-2修复:refreshToken必须发生轮转")
  396. newClaims, perr := authHelper.ParseRefreshToken(resp.RefreshToken, cfg.Auth.RefreshSecret)
  397. require.NoError(t, perr)
  398. assert.Equal(t, int64(1), newClaims.TokenVersion, "新 refreshToken 必须携带递增后的 tokenVersion")
  399. assert.True(t, resp.Expires > time.Now().Unix(), "expires应为未来的unix时间戳")
  400. }
  401. // TC-0244: token无效
  402. func TestRefreshToken_InvalidToken(t *testing.T) {
  403. ctx := context.Background()
  404. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  405. srv := NewPermServer(svcCtx)
  406. _, err := srv.RefreshToken(ctx, &pb.RefreshTokenReq{
  407. RefreshToken: "invalid.token.string",
  408. })
  409. require.Error(t, err)
  410. assert.Equal(t, codes.Unauthenticated, status.Code(err))
  411. assert.Equal(t, "refreshToken无效或已过期", status.Convert(err).Message())
  412. }
  413. // TC-0245: 账号冻结
  414. func TestRefreshToken_AccountFrozen(t *testing.T) {
  415. ctx := context.Background()
  416. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  417. conn := testutil.GetTestSqlConn()
  418. now := time.Now().Unix()
  419. uid := testutil.UniqueId()
  420. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  421. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  422. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  423. Status: 2, CreateTime: now, UpdateTime: now,
  424. })
  425. require.NoError(t, err)
  426. uId, _ := uRes.LastInsertId()
  427. t.Cleanup(func() {
  428. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  429. })
  430. cfg := testutil.GetTestConfig()
  431. refreshToken, err := authHelper.GenerateRefreshToken(cfg.Auth.RefreshSecret, cfg.Auth.RefreshExpire, uId, "", 0)
  432. require.NoError(t, err)
  433. srv := NewPermServer(svcCtx)
  434. _, err = srv.RefreshToken(ctx, &pb.RefreshTokenReq{
  435. RefreshToken: refreshToken,
  436. })
  437. require.Error(t, err)
  438. assert.Equal(t, codes.PermissionDenied, status.Code(err))
  439. assert.Equal(t, "账号已被冻结", status.Convert(err).Message())
  440. }
  441. // TC-0246: productCode回退到claims
  442. func TestRefreshToken_FallbackToClaimsProductCode(t *testing.T) {
  443. ctx := context.Background()
  444. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  445. conn := testutil.GetTestSqlConn()
  446. now := time.Now().Unix()
  447. uid := testutil.UniqueId()
  448. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  449. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  450. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  451. Status: 1, CreateTime: now, UpdateTime: now,
  452. })
  453. require.NoError(t, err)
  454. uId, _ := uRes.LastInsertId()
  455. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  456. Code: uid, Name: "test_prod", AppKey: uid + "_k", AppSecret: "s1",
  457. Status: 1, CreateTime: now, UpdateTime: now,
  458. })
  459. require.NoError(t, err)
  460. pId, _ := pRes.LastInsertId()
  461. mbrRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  462. ProductCode: uid, UserId: uId, MemberType: "MEMBER",
  463. Status: 1, CreateTime: now, UpdateTime: now,
  464. })
  465. require.NoError(t, err)
  466. mbrId, _ := mbrRes.LastInsertId()
  467. t.Cleanup(func() {
  468. testutil.CleanTable(ctx, conn, "`sys_product_member`", mbrId)
  469. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  470. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  471. })
  472. cfg := testutil.GetTestConfig()
  473. refreshToken, err := authHelper.GenerateRefreshToken(cfg.Auth.RefreshSecret, cfg.Auth.RefreshExpire, uId, uid, 0)
  474. require.NoError(t, err)
  475. srv := NewPermServer(svcCtx)
  476. resp, err := srv.RefreshToken(ctx, &pb.RefreshTokenReq{
  477. RefreshToken: refreshToken,
  478. ProductCode: "",
  479. })
  480. require.NoError(t, err)
  481. assert.NotEmpty(t, resp.AccessToken)
  482. assert.NotEqual(t, refreshToken, resp.RefreshToken, "M-2修复:refreshToken必须发生轮转")
  483. newClaims, perr := authHelper.ParseRefreshToken(resp.RefreshToken, cfg.Auth.RefreshSecret)
  484. require.NoError(t, perr)
  485. assert.Equal(t, int64(1), newClaims.TokenVersion, "新 refreshToken 必须携带递增后的 tokenVersion")
  486. assert.Equal(t, uid, newClaims.ProductCode, "fallback 分支:应使用 claims.ProductCode")
  487. }
  488. // TC-0247: 超管+productCode
  489. func TestRefreshToken_SuperAdminWithProductCode(t *testing.T) {
  490. ctx := context.Background()
  491. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  492. conn := testutil.GetTestSqlConn()
  493. now := time.Now().Unix()
  494. uid := testutil.UniqueId()
  495. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  496. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "sa",
  497. Avatar: sql.NullString{}, IsSuperAdmin: 1, MustChangePassword: 2,
  498. Status: 1, CreateTime: now, UpdateTime: now,
  499. })
  500. require.NoError(t, err)
  501. uId, _ := uRes.LastInsertId()
  502. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  503. Code: uid, Name: "test_prod", AppKey: uid + "_k", AppSecret: "s1",
  504. Status: 1, CreateTime: now, UpdateTime: now,
  505. })
  506. require.NoError(t, err)
  507. pId, _ := pRes.LastInsertId()
  508. pm1Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  509. ProductCode: uid, Name: "p1", Code: uid + "_c1",
  510. Status: 1, CreateTime: now, UpdateTime: now,
  511. })
  512. require.NoError(t, err)
  513. pm1Id, _ := pm1Res.LastInsertId()
  514. t.Cleanup(func() {
  515. testutil.CleanTable(ctx, conn, "`sys_perm`", pm1Id)
  516. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  517. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  518. })
  519. cfg := testutil.GetTestConfig()
  520. refreshToken, err := authHelper.GenerateRefreshToken(cfg.Auth.RefreshSecret, cfg.Auth.RefreshExpire, uId, uid, 0)
  521. require.NoError(t, err)
  522. srv := NewPermServer(svcCtx)
  523. resp, err := srv.RefreshToken(ctx, &pb.RefreshTokenReq{
  524. RefreshToken: refreshToken,
  525. ProductCode: uid,
  526. })
  527. require.NoError(t, err)
  528. assert.NotEmpty(t, resp.AccessToken)
  529. assert.NotEqual(t, refreshToken, resp.RefreshToken, "M-2修复:refreshToken必须发生轮转")
  530. newClaims, perr := authHelper.ParseRefreshToken(resp.RefreshToken, cfg.Auth.RefreshSecret)
  531. require.NoError(t, perr)
  532. assert.Equal(t, int64(1), newClaims.TokenVersion, "新 refreshToken 必须携带递增后的 tokenVersion")
  533. }
  534. // TC-0248: 普通用户+productCode
  535. func TestRefreshToken_NormalUserWithProductCode(t *testing.T) {
  536. ctx := context.Background()
  537. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  538. conn := testutil.GetTestSqlConn()
  539. now := time.Now().Unix()
  540. uid := testutil.UniqueId()
  541. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  542. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  543. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  544. Status: 1, CreateTime: now, UpdateTime: now,
  545. })
  546. require.NoError(t, err)
  547. uId, _ := uRes.LastInsertId()
  548. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  549. Code: uid, Name: "test_prod", AppKey: uid + "_k", AppSecret: "s1",
  550. Status: 1, CreateTime: now, UpdateTime: now,
  551. })
  552. require.NoError(t, err)
  553. pId, _ := pRes.LastInsertId()
  554. mbrRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  555. ProductCode: uid, UserId: uId, MemberType: "MEMBER",
  556. Status: 1, CreateTime: now, UpdateTime: now,
  557. })
  558. require.NoError(t, err)
  559. mbrId, _ := mbrRes.LastInsertId()
  560. pm1Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  561. ProductCode: uid, Name: "p1", Code: uid + "_c1",
  562. Status: 1, CreateTime: now, UpdateTime: now,
  563. })
  564. require.NoError(t, err)
  565. pm1Id, _ := pm1Res.LastInsertId()
  566. roleRes, err := svcCtx.SysRoleModel.Insert(ctx, &roleModel.SysRole{
  567. ProductCode: uid, Name: uid + "_role", Status: 1, PermsLevel: 1,
  568. CreateTime: now, UpdateTime: now,
  569. })
  570. require.NoError(t, err)
  571. roleId, _ := roleRes.LastInsertId()
  572. urRes, err := svcCtx.SysUserRoleModel.Insert(ctx, &userRoleModel.SysUserRole{
  573. UserId: uId, RoleId: roleId, CreateTime: now, UpdateTime: now,
  574. })
  575. require.NoError(t, err)
  576. urId, _ := urRes.LastInsertId()
  577. rpRes, err := svcCtx.SysRolePermModel.Insert(ctx, &rolePermModel.SysRolePerm{
  578. RoleId: roleId, PermId: pm1Id, CreateTime: now, UpdateTime: now,
  579. })
  580. require.NoError(t, err)
  581. rpId, _ := rpRes.LastInsertId()
  582. t.Cleanup(func() {
  583. testutil.CleanTable(ctx, conn, "`sys_role_perm`", rpId)
  584. testutil.CleanTable(ctx, conn, "`sys_user_role`", urId)
  585. testutil.CleanTable(ctx, conn, "`sys_perm`", pm1Id)
  586. testutil.CleanTable(ctx, conn, "`sys_role`", roleId)
  587. testutil.CleanTable(ctx, conn, "`sys_product_member`", mbrId)
  588. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  589. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  590. })
  591. cfg := testutil.GetTestConfig()
  592. refreshToken, err := authHelper.GenerateRefreshToken(cfg.Auth.RefreshSecret, cfg.Auth.RefreshExpire, uId, uid, 0)
  593. require.NoError(t, err)
  594. srv := NewPermServer(svcCtx)
  595. resp, err := srv.RefreshToken(ctx, &pb.RefreshTokenReq{
  596. RefreshToken: refreshToken,
  597. ProductCode: uid,
  598. })
  599. require.NoError(t, err)
  600. assert.NotEmpty(t, resp.AccessToken)
  601. assert.NotEqual(t, refreshToken, resp.RefreshToken, "M-2修复:refreshToken必须发生轮转")
  602. newClaims, perr := authHelper.ParseRefreshToken(resp.RefreshToken, cfg.Auth.RefreshSecret)
  603. require.NoError(t, perr)
  604. assert.Equal(t, int64(1), newClaims.TokenVersion, "新 refreshToken 必须携带递增后的 tokenVersion")
  605. }
  606. // ---------- VerifyToken ----------
  607. // TC-0249: 有效token(VerifyToken 现在实时查询DB,需要真实数据)
  608. func TestVerifyToken_Valid(t *testing.T) {
  609. ctx := context.Background()
  610. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  611. cfg := testutil.GetTestConfig()
  612. conn := testutil.GetTestSqlConn()
  613. ts := time.Now().Unix()
  614. uid := testutil.UniqueId()
  615. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  616. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick_verify",
  617. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  618. Status: 1, CreateTime: ts, UpdateTime: ts,
  619. })
  620. require.NoError(t, err)
  621. uId, _ := uRes.LastInsertId()
  622. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  623. Code: uid, Name: "prod_verify", AppKey: uid + "_k", AppSecret: "s1",
  624. Status: 1, CreateTime: ts, UpdateTime: ts,
  625. })
  626. require.NoError(t, err)
  627. pId, _ := pRes.LastInsertId()
  628. pmRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  629. ProductCode: uid, UserId: uId, MemberType: "ADMIN", Status: 1,
  630. CreateTime: ts, UpdateTime: ts,
  631. })
  632. require.NoError(t, err)
  633. pmId, _ := pmRes.LastInsertId()
  634. pm1Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  635. ProductCode: uid, Name: "perm_a", Code: "perm_a",
  636. Status: 1, CreateTime: ts, UpdateTime: ts,
  637. })
  638. require.NoError(t, err)
  639. pm1Id, _ := pm1Res.LastInsertId()
  640. pm2Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  641. ProductCode: uid, Name: "perm_b", Code: "perm_b",
  642. Status: 1, CreateTime: ts, UpdateTime: ts,
  643. })
  644. require.NoError(t, err)
  645. pm2Id, _ := pm2Res.LastInsertId()
  646. t.Cleanup(func() {
  647. svcCtx.UserDetailsLoader.Del(ctx, uId, uid)
  648. testutil.CleanTable(ctx, conn, "`sys_perm`", pm1Id, pm2Id)
  649. testutil.CleanTable(ctx, conn, "`sys_product_member`", pmId)
  650. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  651. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  652. })
  653. svcCtx.UserDetailsLoader.Del(ctx, uId, uid)
  654. accessToken, err := authHelper.GenerateAccessToken(
  655. cfg.Auth.AccessSecret, cfg.Auth.AccessExpire,
  656. uId, uid, uid, "ADMIN", 0,
  657. )
  658. require.NoError(t, err)
  659. srv := NewPermServer(svcCtx)
  660. resp, err := srv.VerifyToken(ctx, &pb.VerifyTokenReq{AccessToken: accessToken})
  661. require.NoError(t, err)
  662. assert.True(t, resp.Valid)
  663. assert.Equal(t, uId, resp.UserId)
  664. assert.Equal(t, uid, resp.Username)
  665. assert.Equal(t, "ADMIN", resp.MemberType)
  666. assert.ElementsMatch(t, []string{"perm_a", "perm_b"}, resp.Perms)
  667. // BUG-02: proto定义了productCode字段,实现应返回产品编码
  668. assert.Equal(t, uid, resp.ProductCode, "BUG-02: VerifyTokenResp.ProductCode 应返回产品编码而非空字符串")
  669. }
  670. // TC-0250: 无效token
  671. func TestVerifyToken_Invalid(t *testing.T) {
  672. ctx := context.Background()
  673. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  674. srv := NewPermServer(svcCtx)
  675. resp, err := srv.VerifyToken(ctx, &pb.VerifyTokenReq{AccessToken: "invalid.token.here"})
  676. require.NoError(t, err)
  677. assert.False(t, resp.Valid)
  678. }
  679. // TC-0251: 缺少userId
  680. func TestVerifyToken_MissingUserId(t *testing.T) {
  681. ctx := context.Background()
  682. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  683. cfg := testutil.GetTestConfig()
  684. // Generate a token without userId by using raw JWT
  685. token := createTokenWithoutUserId(cfg.Auth.AccessSecret)
  686. srv := NewPermServer(svcCtx)
  687. resp, err := srv.VerifyToken(ctx, &pb.VerifyTokenReq{AccessToken: token})
  688. require.NoError(t, err)
  689. assert.False(t, resp.Valid)
  690. }
  691. // ---------- GetUserPerms ----------
  692. // TC-0255: 用户不存在
  693. func TestGetUserPerms_UserNotFound(t *testing.T) {
  694. ctx := context.Background()
  695. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  696. conn := testutil.GetTestSqlConn()
  697. now := time.Now().Unix()
  698. uid := testutil.UniqueId()
  699. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  700. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: bcryptHash(t, "secret1"),
  701. Status: 1, CreateTime: now, UpdateTime: now,
  702. })
  703. require.NoError(t, err)
  704. pId, _ := pRes.LastInsertId()
  705. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_product`", pId) })
  706. srv := NewPermServer(svcCtx)
  707. _, err = srv.GetUserPerms(ctx, &pb.GetUserPermsReq{
  708. UserId: 999999999,
  709. ProductCode: uid,
  710. AppKey: uid,
  711. AppSecret: "secret1",
  712. })
  713. require.Error(t, err)
  714. assert.Equal(t, codes.NotFound, status.Code(err))
  715. // 审计 L-R10-10:userId 不存在与非成员合并为同一响应,消除跨产品枚举 oracle
  716. assert.Equal(t, "用户不是该产品的有效成员", status.Convert(err).Message())
  717. }
  718. // TC-0256: 超管
  719. func TestGetUserPerms_SuperAdmin(t *testing.T) {
  720. ctx := context.Background()
  721. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  722. conn := testutil.GetTestSqlConn()
  723. now := time.Now().Unix()
  724. uid := testutil.UniqueId()
  725. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  726. Username: uid, Password: testutil.HashPassword("pass"), Nickname: "sa",
  727. Avatar: sql.NullString{}, IsSuperAdmin: 1, MustChangePassword: 2,
  728. Status: 1, CreateTime: now, UpdateTime: now,
  729. })
  730. require.NoError(t, err)
  731. uId, _ := uRes.LastInsertId()
  732. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  733. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: bcryptHash(t, "secret1"),
  734. Status: 1, CreateTime: now, UpdateTime: now,
  735. })
  736. require.NoError(t, err)
  737. pId, _ := pRes.LastInsertId()
  738. pm1Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  739. ProductCode: uid, Name: "p1", Code: uid + "_c1",
  740. Status: 1, CreateTime: now, UpdateTime: now,
  741. })
  742. require.NoError(t, err)
  743. pm1Id, _ := pm1Res.LastInsertId()
  744. mRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  745. ProductCode: uid, UserId: uId, MemberType: "ADMIN",
  746. Status: 1, CreateTime: now, UpdateTime: now,
  747. })
  748. require.NoError(t, err)
  749. mId, _ := mRes.LastInsertId()
  750. t.Cleanup(func() {
  751. testutil.CleanTable(ctx, conn, "`sys_product_member`", mId)
  752. testutil.CleanTable(ctx, conn, "`sys_perm`", pm1Id)
  753. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  754. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  755. })
  756. srv := NewPermServer(svcCtx)
  757. resp, err := srv.GetUserPerms(ctx, &pb.GetUserPermsReq{
  758. UserId: uId,
  759. ProductCode: uid,
  760. AppKey: uid,
  761. AppSecret: "secret1",
  762. })
  763. require.NoError(t, err)
  764. assert.Equal(t, "SUPER_ADMIN", resp.MemberType)
  765. assert.Contains(t, resp.Perms, uid+"_c1")
  766. }
  767. // TC-0234: 验证disabled计数
  768. func TestSyncPermissions_VerifyDisabledCount(t *testing.T) {
  769. ctx := context.Background()
  770. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  771. conn := testutil.GetTestSqlConn()
  772. now := time.Now().Unix()
  773. uid := testutil.UniqueId()
  774. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  775. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: bcryptHash(t, "secret1"),
  776. Status: 1, CreateTime: now, UpdateTime: now,
  777. })
  778. require.NoError(t, err)
  779. pId, _ := pRes.LastInsertId()
  780. var permIds []int64
  781. for i := 0; i < 5; i++ {
  782. pmRes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  783. ProductCode: uid, Name: "p", Code: fmt.Sprintf("%s_c%d", uid, i),
  784. Status: 1, CreateTime: now, UpdateTime: now,
  785. })
  786. require.NoError(t, err)
  787. pmId, _ := pmRes.LastInsertId()
  788. permIds = append(permIds, pmId)
  789. }
  790. t.Cleanup(func() {
  791. testutil.CleanTable(ctx, conn, "`sys_perm`", permIds...)
  792. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  793. })
  794. srv := NewPermServer(svcCtx)
  795. resp, err := srv.SyncPermissions(ctx, &pb.SyncPermissionsReq{
  796. AppKey: uid,
  797. AppSecret: "secret1",
  798. Perms: []*pb.PermItem{
  799. {Code: fmt.Sprintf("%s_c0", uid), Name: "p"},
  800. {Code: fmt.Sprintf("%s_c1", uid), Name: "p"},
  801. },
  802. })
  803. require.NoError(t, err)
  804. assert.Equal(t, int64(3), resp.Disabled)
  805. }
  806. // TC-0257: MEMBER-DENY覆盖
  807. func TestGetUserPerms_MemberDENYOverride(t *testing.T) {
  808. ctx := context.Background()
  809. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  810. conn := testutil.GetTestSqlConn()
  811. now := time.Now().Unix()
  812. uid := testutil.UniqueId()
  813. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  814. Username: uid, Password: testutil.HashPassword("pass"), Nickname: "nick",
  815. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  816. Status: 1, CreateTime: now, UpdateTime: now,
  817. })
  818. require.NoError(t, err)
  819. uId, _ := uRes.LastInsertId()
  820. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  821. Code: uid, Name: "test_prod", AppKey: uid + "_k", AppSecret: bcryptHash(t, "secret1"),
  822. Status: 1, CreateTime: now, UpdateTime: now,
  823. })
  824. require.NoError(t, err)
  825. pId, _ := pRes.LastInsertId()
  826. mbrRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  827. ProductCode: uid, UserId: uId, MemberType: "MEMBER",
  828. Status: 1, CreateTime: now, UpdateTime: now,
  829. })
  830. require.NoError(t, err)
  831. mbrId, _ := mbrRes.LastInsertId()
  832. roleRes, err := svcCtx.SysRoleModel.Insert(ctx, &roleModel.SysRole{
  833. ProductCode: uid, Name: uid + "_role", Status: 1, PermsLevel: 1,
  834. CreateTime: now, UpdateTime: now,
  835. })
  836. require.NoError(t, err)
  837. roleId, _ := roleRes.LastInsertId()
  838. permARes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  839. ProductCode: uid, Name: "permA", Code: uid + "_pA",
  840. Status: 1, CreateTime: now, UpdateTime: now,
  841. })
  842. require.NoError(t, err)
  843. permAId, _ := permARes.LastInsertId()
  844. permBRes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  845. ProductCode: uid, Name: "permB", Code: uid + "_pB",
  846. Status: 1, CreateTime: now, UpdateTime: now,
  847. })
  848. require.NoError(t, err)
  849. permBId, _ := permBRes.LastInsertId()
  850. urRes, err := svcCtx.SysUserRoleModel.Insert(ctx, &userRoleModel.SysUserRole{
  851. UserId: uId, RoleId: roleId, CreateTime: now, UpdateTime: now,
  852. })
  853. require.NoError(t, err)
  854. urId, _ := urRes.LastInsertId()
  855. rpARes, err := svcCtx.SysRolePermModel.Insert(ctx, &rolePermModel.SysRolePerm{
  856. RoleId: roleId, PermId: permAId, CreateTime: now, UpdateTime: now,
  857. })
  858. require.NoError(t, err)
  859. rpAId, _ := rpARes.LastInsertId()
  860. rpBRes, err := svcCtx.SysRolePermModel.Insert(ctx, &rolePermModel.SysRolePerm{
  861. RoleId: roleId, PermId: permBId, CreateTime: now, UpdateTime: now,
  862. })
  863. require.NoError(t, err)
  864. rpBId, _ := rpBRes.LastInsertId()
  865. upRes, err := svcCtx.SysUserPermModel.Insert(ctx, &userPermModel.SysUserPerm{
  866. UserId: uId, PermId: permAId, Effect: "DENY",
  867. CreateTime: now, UpdateTime: now,
  868. })
  869. require.NoError(t, err)
  870. upId, _ := upRes.LastInsertId()
  871. t.Cleanup(func() {
  872. testutil.CleanTable(ctx, conn, "`sys_user_perm`", upId)
  873. testutil.CleanTable(ctx, conn, "`sys_role_perm`", rpAId, rpBId)
  874. testutil.CleanTable(ctx, conn, "`sys_user_role`", urId)
  875. testutil.CleanTable(ctx, conn, "`sys_perm`", permAId, permBId)
  876. testutil.CleanTable(ctx, conn, "`sys_role`", roleId)
  877. testutil.CleanTable(ctx, conn, "`sys_product_member`", mbrId)
  878. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  879. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  880. })
  881. srv := NewPermServer(svcCtx)
  882. resp, err := srv.GetUserPerms(ctx, &pb.GetUserPermsReq{
  883. UserId: uId,
  884. ProductCode: uid,
  885. AppKey: uid + "_k",
  886. AppSecret: "secret1",
  887. })
  888. require.NoError(t, err)
  889. assert.Equal(t, "MEMBER", resp.MemberType)
  890. assert.Contains(t, resp.Perms, uid+"_pB")
  891. assert.NotContains(t, resp.Perms, uid+"_pA")
  892. }
  893. // TC-0252: gRPC VerifyToken 用户已冻结返回valid=false(H-4修复验证)
  894. func TestVerifyToken_FrozenUserReturnsInvalid(t *testing.T) {
  895. ctx := context.Background()
  896. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  897. conn := testutil.GetTestSqlConn()
  898. now := time.Now().Unix()
  899. uid := testutil.UniqueId()
  900. cfg := testutil.GetTestConfig()
  901. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  902. Username: uid, Password: testutil.HashPassword("pass"), Nickname: "frozen",
  903. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  904. Status: 2, CreateTime: now, UpdateTime: now,
  905. })
  906. require.NoError(t, err)
  907. uId, _ := uRes.LastInsertId()
  908. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_user`", uId) })
  909. accessToken, err := authHelper.GenerateAccessToken(
  910. cfg.Auth.AccessSecret, cfg.Auth.AccessExpire,
  911. uId, uid, "", "MEMBER", 0,
  912. )
  913. require.NoError(t, err)
  914. srv := NewPermServer(svcCtx)
  915. resp, err := srv.VerifyToken(ctx, &pb.VerifyTokenReq{AccessToken: accessToken})
  916. require.NoError(t, err)
  917. assert.False(t, resp.Valid, "frozen user token should be invalid")
  918. }
  919. // TC-0253: gRPC VerifyToken 非产品成员返回valid=false(H-4修复验证)
  920. func TestVerifyToken_NonMemberReturnsInvalid(t *testing.T) {
  921. ctx := context.Background()
  922. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  923. conn := testutil.GetTestSqlConn()
  924. now := time.Now().Unix()
  925. uid := testutil.UniqueId()
  926. pc := testutil.UniqueId()
  927. cfg := testutil.GetTestConfig()
  928. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  929. Username: uid, Password: testutil.HashPassword("pass"), Nickname: "user",
  930. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  931. Status: 1, CreateTime: now, UpdateTime: now,
  932. })
  933. require.NoError(t, err)
  934. uId, _ := uRes.LastInsertId()
  935. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  936. Code: pc, Name: "prod", AppKey: testutil.UniqueId(), AppSecret: "s",
  937. Status: 1, CreateTime: now, UpdateTime: now,
  938. })
  939. require.NoError(t, err)
  940. pId, _ := pRes.LastInsertId()
  941. t.Cleanup(func() {
  942. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  943. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  944. })
  945. accessToken, err := authHelper.GenerateAccessToken(
  946. cfg.Auth.AccessSecret, cfg.Auth.AccessExpire,
  947. uId, uid, pc, "MEMBER", 0,
  948. )
  949. require.NoError(t, err)
  950. srv := NewPermServer(svcCtx)
  951. resp, err := srv.VerifyToken(ctx, &pb.VerifyTokenReq{AccessToken: accessToken})
  952. require.NoError(t, err)
  953. assert.False(t, resp.Valid, "non-member user with productCode should be invalid")
  954. }
  955. // TC-0254: gRPC VerifyToken 返回实时权限和成员类型(H-4修复验证)
  956. func TestVerifyToken_ReturnsRealtimeData(t *testing.T) {
  957. ctx := context.Background()
  958. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  959. conn := testutil.GetTestSqlConn()
  960. now := time.Now().Unix()
  961. uid := testutil.UniqueId()
  962. cfg := testutil.GetTestConfig()
  963. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  964. Username: uid, Password: testutil.HashPassword("pass"), Nickname: "user",
  965. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  966. Status: 1, CreateTime: now, UpdateTime: now,
  967. })
  968. require.NoError(t, err)
  969. uId, _ := uRes.LastInsertId()
  970. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  971. Code: uid, Name: "prod", AppKey: uid + "_k", AppSecret: "s",
  972. Status: 1, CreateTime: now, UpdateTime: now,
  973. })
  974. require.NoError(t, err)
  975. pId, _ := pRes.LastInsertId()
  976. mbrRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  977. ProductCode: uid, UserId: uId, MemberType: "ADMIN",
  978. Status: 1, CreateTime: now, UpdateTime: now,
  979. })
  980. require.NoError(t, err)
  981. mbrId, _ := mbrRes.LastInsertId()
  982. permRes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  983. ProductCode: uid, Name: "realtime_perm", Code: uid + "_rt",
  984. Status: 1, CreateTime: now, UpdateTime: now,
  985. })
  986. require.NoError(t, err)
  987. permId, _ := permRes.LastInsertId()
  988. t.Cleanup(func() {
  989. testutil.CleanTable(ctx, conn, "`sys_perm`", permId)
  990. testutil.CleanTable(ctx, conn, "`sys_product_member`", mbrId)
  991. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  992. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  993. })
  994. accessToken, err := authHelper.GenerateAccessToken(
  995. cfg.Auth.AccessSecret, cfg.Auth.AccessExpire,
  996. uId, uid, uid, "MEMBER", 0,
  997. )
  998. require.NoError(t, err)
  999. svcCtx.UserDetailsLoader.Clean(ctx, uId)
  1000. srv := NewPermServer(svcCtx)
  1001. resp, err := srv.VerifyToken(ctx, &pb.VerifyTokenReq{AccessToken: accessToken})
  1002. require.NoError(t, err)
  1003. assert.True(t, resp.Valid)
  1004. assert.Equal(t, "ADMIN", resp.MemberType, "should return realtime memberType, not token's")
  1005. assert.Contains(t, resp.Perms, uid+"_rt", "should return realtime perms")
  1006. }
  1007. // TC-0241: gRPC Login 产品成员被禁用时拒绝(H-3修复验证)
  1008. func TestLogin_DisabledMemberRejected(t *testing.T) {
  1009. ctx := context.Background()
  1010. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  1011. conn := testutil.GetTestSqlConn()
  1012. now := time.Now().Unix()
  1013. uid := testutil.UniqueId()
  1014. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  1015. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  1016. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  1017. Status: 1, CreateTime: now, UpdateTime: now,
  1018. })
  1019. require.NoError(t, err)
  1020. uId, _ := uRes.LastInsertId()
  1021. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  1022. Code: uid, Name: "prod", AppKey: uid + "_k", AppSecret: "s1",
  1023. Status: 1, CreateTime: now, UpdateTime: now,
  1024. })
  1025. require.NoError(t, err)
  1026. pId, _ := pRes.LastInsertId()
  1027. pmRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  1028. ProductCode: uid, UserId: uId, MemberType: "MEMBER", Status: 2,
  1029. CreateTime: now, UpdateTime: now,
  1030. })
  1031. require.NoError(t, err)
  1032. pmId, _ := pmRes.LastInsertId()
  1033. t.Cleanup(func() {
  1034. testutil.CleanTable(ctx, conn, "`sys_product_member`", pmId)
  1035. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  1036. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  1037. })
  1038. srv := NewPermServer(svcCtx)
  1039. _, err = srv.Login(ctx, &pb.LoginReq{
  1040. Username: uid,
  1041. Password: "pass123",
  1042. ProductCode: uid,
  1043. })
  1044. require.Error(t, err)
  1045. assert.Equal(t, codes.PermissionDenied, status.Code(err))
  1046. // 审计 M-R10-5:loginService 删除了多余的 FindOneByProductCodeUserId,改由 UD.MemberType==""
  1047. // 做统一判定,非成员/禁用成员合并为同一文案
  1048. assert.Equal(t, "您不是该产品的有效成员", status.Convert(err).Message())
  1049. }
  1050. // helper: create a JWT with no userId claim
  1051. func createTokenWithoutUserId(secret string) string {
  1052. claims := jwt.MapClaims{
  1053. "username": "test",
  1054. "exp": time.Now().Add(time.Hour).Unix(),
  1055. }
  1056. token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
  1057. s, _ := token.SignedString([]byte(secret))
  1058. return s
  1059. }
  1060. // =============================================================================
  1061. // audit H-2 修复回归测试:gRPC GetUserPerms 必须对齐 VerifyToken 的状态校验
  1062. // 修复前:GetUserPerms 仅校验"用户存在";冻结用户/被踢出产品的用户仍会被返回全量权限。
  1063. // 修复后:增加 StatusEnabled 判定 + (非超管下)MemberType 非空判定。
  1064. // =============================================================================
  1065. // TC-0700: GetUserPerms 对冻结用户 (Status=Disabled) 必须返回 PermissionDenied
  1066. func TestGetUserPerms_FrozenUser_PermissionDenied(t *testing.T) {
  1067. ctx := context.Background()
  1068. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  1069. conn := testutil.GetTestSqlConn()
  1070. now := time.Now().Unix()
  1071. uid := testutil.UniqueId()
  1072. // 用户 Status=2 (Disabled)
  1073. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  1074. Username: uid, Password: testutil.HashPassword("pass"), Nickname: "frozen",
  1075. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  1076. Status: 2, CreateTime: now, UpdateTime: now,
  1077. })
  1078. require.NoError(t, err)
  1079. uId, _ := uRes.LastInsertId()
  1080. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  1081. Code: uid, Name: "prod", AppKey: uid + "_k", AppSecret: bcryptHash(t, "s"),
  1082. Status: 1, CreateTime: now, UpdateTime: now,
  1083. })
  1084. require.NoError(t, err)
  1085. pId, _ := pRes.LastInsertId()
  1086. // 插入该产品下启用成员,保证 MemberType != "",排除冻结用户与非成员两个判定路径的干扰
  1087. mRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  1088. ProductCode: uid, UserId: uId, MemberType: "MEMBER", Status: 1,
  1089. CreateTime: now, UpdateTime: now,
  1090. })
  1091. require.NoError(t, err)
  1092. mId, _ := mRes.LastInsertId()
  1093. t.Cleanup(func() {
  1094. testutil.CleanTable(ctx, conn, "`sys_product_member`", mId)
  1095. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  1096. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  1097. })
  1098. // 清理缓存确保 loader 从 DB 取最新的 Status=2
  1099. svcCtx.UserDetailsLoader.Clean(ctx, uId)
  1100. srv := NewPermServer(svcCtx)
  1101. _, err = srv.GetUserPerms(ctx, &pb.GetUserPermsReq{
  1102. UserId: uId, ProductCode: uid, AppKey: uid + "_k", AppSecret: "s",
  1103. })
  1104. require.Error(t, err, "冻结用户的 GetUserPerms 必须返回错误,不能再返回全量权限")
  1105. assert.Equal(t, codes.PermissionDenied, status.Code(err),
  1106. "audit H-2: 冻结用户应返回 PermissionDenied 以阻断跨系统一致性漏洞")
  1107. assert.Contains(t, status.Convert(err).Message(), "冻结")
  1108. }
  1109. // TC-0701: GetUserPerms 对已被移出产品的启用用户(非超管 + MemberType 空)必须返回 PermissionDenied
  1110. func TestGetUserPerms_NonMember_PermissionDenied(t *testing.T) {
  1111. ctx := context.Background()
  1112. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  1113. conn := testutil.GetTestSqlConn()
  1114. now := time.Now().Unix()
  1115. uid := testutil.UniqueId()
  1116. // 用户启用但不是目标产品的成员
  1117. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  1118. Username: uid, Password: testutil.HashPassword("pass"), Nickname: "non_member",
  1119. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  1120. Status: 1, CreateTime: now, UpdateTime: now,
  1121. })
  1122. require.NoError(t, err)
  1123. uId, _ := uRes.LastInsertId()
  1124. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  1125. Code: uid, Name: "prod", AppKey: uid + "_k", AppSecret: bcryptHash(t, "s"),
  1126. Status: 1, CreateTime: now, UpdateTime: now,
  1127. })
  1128. require.NoError(t, err)
  1129. pId, _ := pRes.LastInsertId()
  1130. t.Cleanup(func() {
  1131. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  1132. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  1133. })
  1134. svcCtx.UserDetailsLoader.Clean(ctx, uId)
  1135. srv := NewPermServer(svcCtx)
  1136. _, err = srv.GetUserPerms(ctx, &pb.GetUserPermsReq{
  1137. UserId: uId, ProductCode: uid, AppKey: uid + "_k", AppSecret: "s",
  1138. })
  1139. require.Error(t, err)
  1140. // 审计 L-R10-10:与"userId 不存在"合并为 NotFound,关闭跨产品枚举 oracle
  1141. assert.Equal(t, codes.NotFound, status.Code(err),
  1142. "audit L-R10-10: 用户不是产品成员时应返回 NotFound,与 Username 为空的分支同码")
  1143. assert.Contains(t, status.Convert(err).Message(), "成员")
  1144. }
  1145. // TC-0702: GetUserPerms 对"产品成员被禁用的 DEV 部门用户"必须返回 PermissionDenied
  1146. // 组合 H-2 + H-3 的交叉场景:禁用成员 → MemberType 清空 → 即便 DeptType=DEV 也不应获得权限
  1147. func TestGetUserPerms_DisabledMemberInDevDept_PermissionDenied(t *testing.T) {
  1148. ctx := context.Background()
  1149. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  1150. conn := testutil.GetTestSqlConn()
  1151. now := time.Now().Unix()
  1152. uid := testutil.UniqueId()
  1153. // 插入 DEV 部门
  1154. deptRes, err := svcCtx.SysDeptModel.Insert(ctx, &deptModel.SysDept{
  1155. Name: "dev_" + uid, ParentId: 0, Path: "/",
  1156. DeptType: "DEV", Status: 1, CreateTime: now, UpdateTime: now,
  1157. })
  1158. require.NoError(t, err)
  1159. deptId, _ := deptRes.LastInsertId()
  1160. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  1161. Username: uid, Password: testutil.HashPassword("pass"), Nickname: "dev_user",
  1162. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2, DeptId: deptId,
  1163. Status: 1, CreateTime: now, UpdateTime: now,
  1164. })
  1165. require.NoError(t, err)
  1166. uId, _ := uRes.LastInsertId()
  1167. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  1168. Code: uid, Name: "prod", AppKey: uid + "_k", AppSecret: bcryptHash(t, "s"),
  1169. Status: 1, CreateTime: now, UpdateTime: now,
  1170. })
  1171. require.NoError(t, err)
  1172. pId, _ := pRes.LastInsertId()
  1173. // 被管理员禁用的产品成员 (Status=2)
  1174. mRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  1175. ProductCode: uid, UserId: uId, MemberType: "MEMBER", Status: 2,
  1176. CreateTime: now, UpdateTime: now,
  1177. })
  1178. require.NoError(t, err)
  1179. mId, _ := mRes.LastInsertId()
  1180. // 放几条启用权限,验证"本来能拿到"
  1181. permRes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  1182. ProductCode: uid, Name: "all", Code: uid + "_all",
  1183. Status: 1, CreateTime: now, UpdateTime: now,
  1184. })
  1185. require.NoError(t, err)
  1186. permId, _ := permRes.LastInsertId()
  1187. t.Cleanup(func() {
  1188. testutil.CleanTable(ctx, conn, "`sys_perm`", permId)
  1189. testutil.CleanTable(ctx, conn, "`sys_product_member`", mId)
  1190. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  1191. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  1192. testutil.CleanTable(ctx, conn, "`sys_dept`", deptId)
  1193. })
  1194. svcCtx.UserDetailsLoader.Clean(ctx, uId)
  1195. srv := NewPermServer(svcCtx)
  1196. _, err = srv.GetUserPerms(ctx, &pb.GetUserPermsReq{
  1197. UserId: uId, ProductCode: uid, AppKey: uid + "_k", AppSecret: "s",
  1198. })
  1199. require.Error(t, err,
  1200. "audit H-3: 产品成员被禁用的 DEV 部门用户不应再被 loadPerms 授予全量权限,"+
  1201. "GetUserPerms 也不应继续返回授权状态")
  1202. // 审计 L-R10-10:非成员合并到 NotFound(禁用成员在 loadMembership 里会把 MemberType 清空)
  1203. assert.Equal(t, codes.NotFound, status.Code(err))
  1204. }
  1205. // TC-0703: GetUserPerms 对"启用的产品成员"返回成功(H-2 回归基准)
  1206. // 验证修复后的正常路径未被误伤
  1207. func TestGetUserPerms_EnabledMember_Succeeds(t *testing.T) {
  1208. ctx := context.Background()
  1209. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  1210. conn := testutil.GetTestSqlConn()
  1211. now := time.Now().Unix()
  1212. uid := testutil.UniqueId()
  1213. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  1214. Username: uid, Password: testutil.HashPassword("pass"), Nickname: "ok",
  1215. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  1216. Status: 1, CreateTime: now, UpdateTime: now,
  1217. })
  1218. require.NoError(t, err)
  1219. uId, _ := uRes.LastInsertId()
  1220. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  1221. Code: uid, Name: "prod", AppKey: uid + "_k", AppSecret: bcryptHash(t, "s"),
  1222. Status: 1, CreateTime: now, UpdateTime: now,
  1223. })
  1224. require.NoError(t, err)
  1225. pId, _ := pRes.LastInsertId()
  1226. mRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  1227. ProductCode: uid, UserId: uId, MemberType: "ADMIN", Status: 1,
  1228. CreateTime: now, UpdateTime: now,
  1229. })
  1230. require.NoError(t, err)
  1231. mId, _ := mRes.LastInsertId()
  1232. permRes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  1233. ProductCode: uid, Name: "p", Code: uid + "_c",
  1234. Status: 1, CreateTime: now, UpdateTime: now,
  1235. })
  1236. require.NoError(t, err)
  1237. permId, _ := permRes.LastInsertId()
  1238. t.Cleanup(func() {
  1239. testutil.CleanTable(ctx, conn, "`sys_perm`", permId)
  1240. testutil.CleanTable(ctx, conn, "`sys_product_member`", mId)
  1241. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  1242. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  1243. })
  1244. srv := NewPermServer(svcCtx)
  1245. resp, err := srv.GetUserPerms(ctx, &pb.GetUserPermsReq{
  1246. UserId: uId, ProductCode: uid, AppKey: uid + "_k", AppSecret: "s",
  1247. })
  1248. require.NoError(t, err)
  1249. assert.Equal(t, "ADMIN", resp.MemberType)
  1250. assert.Contains(t, resp.Perms, uid+"_c")
  1251. }