permserver_test.go 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183
  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. permModel "perms-system-server/internal/model/perm"
  10. productModel "perms-system-server/internal/model/product"
  11. memberModel "perms-system-server/internal/model/productmember"
  12. roleModel "perms-system-server/internal/model/role"
  13. rolePermModel "perms-system-server/internal/model/roleperm"
  14. userModel "perms-system-server/internal/model/user"
  15. userPermModel "perms-system-server/internal/model/userperm"
  16. userRoleModel "perms-system-server/internal/model/userrole"
  17. "perms-system-server/internal/svc"
  18. "perms-system-server/internal/testutil"
  19. "perms-system-server/pb"
  20. "github.com/golang-jwt/jwt/v4"
  21. "github.com/stretchr/testify/assert"
  22. "github.com/stretchr/testify/require"
  23. "golang.org/x/crypto/bcrypt"
  24. "google.golang.org/grpc/codes"
  25. "google.golang.org/grpc/status"
  26. )
  27. func bcryptHash(t *testing.T, plaintext string) string {
  28. t.Helper()
  29. h, err := bcrypt.GenerateFromPassword([]byte(plaintext), bcrypt.MinCost)
  30. require.NoError(t, err)
  31. return string(h)
  32. }
  33. // ---------- SyncPermissions ----------
  34. // TC-0195: 正常同步
  35. func TestSyncPermissions_Normal(t *testing.T) {
  36. ctx := context.Background()
  37. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  38. conn := testutil.GetTestSqlConn()
  39. now := time.Now().Unix()
  40. uid := testutil.UniqueId()
  41. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  42. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: bcryptHash(t, "secret1"),
  43. Status: 1, CreateTime: now, UpdateTime: now,
  44. })
  45. require.NoError(t, err)
  46. pId, _ := pRes.LastInsertId()
  47. t.Cleanup(func() {
  48. testutil.CleanTableByField(ctx, conn, "`sys_perm`", "productCode", uid)
  49. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  50. })
  51. srv := NewPermServer(svcCtx)
  52. resp, err := srv.SyncPermissions(ctx, &pb.SyncPermissionsReq{
  53. AppKey: uid,
  54. AppSecret: "secret1",
  55. Perms: []*pb.PermItem{
  56. {Code: "perm_a", Name: "Perm A", Remark: "remark_a"},
  57. {Code: "perm_b", Name: "Perm B", Remark: "remark_b"},
  58. },
  59. })
  60. require.NoError(t, err)
  61. assert.Equal(t, int64(2), resp.Added)
  62. assert.Equal(t, int64(0), resp.Updated)
  63. assert.Equal(t, int64(0), resp.Disabled)
  64. resp2, err := srv.SyncPermissions(ctx, &pb.SyncPermissionsReq{
  65. AppKey: uid,
  66. AppSecret: "secret1",
  67. Perms: []*pb.PermItem{
  68. {Code: "perm_a", Name: "Perm A Updated", Remark: "remark_a"},
  69. },
  70. })
  71. require.NoError(t, err)
  72. assert.Equal(t, int64(0), resp2.Added)
  73. assert.Equal(t, int64(1), resp2.Updated)
  74. assert.Equal(t, int64(1), resp2.Disabled)
  75. }
  76. // TC-0196: appKey无效
  77. func TestSyncPermissions_InvalidAppKey(t *testing.T) {
  78. ctx := context.Background()
  79. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  80. srv := NewPermServer(svcCtx)
  81. _, err := srv.SyncPermissions(ctx, &pb.SyncPermissionsReq{
  82. AppKey: "nonexistent_key",
  83. AppSecret: "any",
  84. Perms: []*pb.PermItem{{Code: "c", Name: "n"}},
  85. })
  86. require.Error(t, err)
  87. assert.Equal(t, codes.Unauthenticated, status.Code(err))
  88. assert.Equal(t, "无效的appKey", status.Convert(err).Message())
  89. }
  90. // TC-0197: appSecret错误
  91. func TestSyncPermissions_WrongAppSecret(t *testing.T) {
  92. ctx := context.Background()
  93. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  94. conn := testutil.GetTestSqlConn()
  95. now := time.Now().Unix()
  96. uid := testutil.UniqueId()
  97. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  98. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: bcryptHash(t, "real_secret"),
  99. Status: 1, CreateTime: now, UpdateTime: now,
  100. })
  101. require.NoError(t, err)
  102. pId, _ := pRes.LastInsertId()
  103. t.Cleanup(func() {
  104. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  105. })
  106. srv := NewPermServer(svcCtx)
  107. _, err = srv.SyncPermissions(ctx, &pb.SyncPermissionsReq{
  108. AppKey: uid,
  109. AppSecret: "wrong_secret",
  110. Perms: []*pb.PermItem{{Code: "c", Name: "n"}},
  111. })
  112. require.Error(t, err)
  113. assert.Equal(t, codes.Unauthenticated, status.Code(err))
  114. assert.Equal(t, "appSecret验证失败", status.Convert(err).Message())
  115. }
  116. // TC-0198: 产品已禁用
  117. func TestSyncPermissions_ProductDisabled(t *testing.T) {
  118. ctx := context.Background()
  119. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  120. conn := testutil.GetTestSqlConn()
  121. now := time.Now().Unix()
  122. uid := testutil.UniqueId()
  123. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  124. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: bcryptHash(t, "secret1"),
  125. Status: 2, CreateTime: now, UpdateTime: now,
  126. })
  127. require.NoError(t, err)
  128. pId, _ := pRes.LastInsertId()
  129. t.Cleanup(func() {
  130. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  131. })
  132. srv := NewPermServer(svcCtx)
  133. _, err = srv.SyncPermissions(ctx, &pb.SyncPermissionsReq{
  134. AppKey: uid,
  135. AppSecret: "secret1",
  136. Perms: []*pb.PermItem{{Code: "c", Name: "n"}},
  137. })
  138. require.Error(t, err)
  139. assert.Equal(t, codes.PermissionDenied, status.Code(err))
  140. assert.Equal(t, "产品已被禁用", status.Convert(err).Message())
  141. }
  142. // ---------- Login ----------
  143. // TC-0200: 正常登录(普通用户+productCode)
  144. func TestLogin_Normal(t *testing.T) {
  145. ctx := context.Background()
  146. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  147. conn := testutil.GetTestSqlConn()
  148. now := time.Now().Unix()
  149. uid := testutil.UniqueId()
  150. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  151. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  152. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  153. Status: 1, CreateTime: now, UpdateTime: now,
  154. })
  155. require.NoError(t, err)
  156. uId, _ := uRes.LastInsertId()
  157. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  158. Code: uid, Name: "test_prod", AppKey: uid + "_k", AppSecret: "s1",
  159. Status: 1, CreateTime: now, UpdateTime: now,
  160. })
  161. require.NoError(t, err)
  162. pId, _ := pRes.LastInsertId()
  163. pmRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  164. ProductCode: uid, UserId: uId, MemberType: "MEMBER", Status: 1,
  165. CreateTime: now, UpdateTime: now,
  166. })
  167. require.NoError(t, err)
  168. pmId, _ := pmRes.LastInsertId()
  169. t.Cleanup(func() {
  170. testutil.CleanTable(ctx, conn, "`sys_product_member`", pmId)
  171. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  172. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  173. })
  174. srv := NewPermServer(svcCtx)
  175. resp, err := srv.Login(ctx, &pb.LoginReq{
  176. Username: uid,
  177. Password: "pass123",
  178. ProductCode: uid,
  179. })
  180. require.NoError(t, err)
  181. assert.NotEmpty(t, resp.AccessToken)
  182. assert.NotEmpty(t, resp.RefreshToken)
  183. assert.True(t, resp.Expires > time.Now().Unix(), "expires应为未来的unix时间戳")
  184. assert.Equal(t, uId, resp.UserId)
  185. assert.Equal(t, uid, resp.Username)
  186. }
  187. // TC-0201: 用户不存在
  188. func TestLogin_UserNotFound(t *testing.T) {
  189. ctx := context.Background()
  190. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  191. srv := NewPermServer(svcCtx)
  192. _, err := srv.Login(ctx, &pb.LoginReq{
  193. Username: "nonexistent_user_xyz",
  194. Password: "any",
  195. ProductCode: "any_product",
  196. })
  197. require.Error(t, err)
  198. assert.Equal(t, codes.Unauthenticated, status.Code(err))
  199. assert.Equal(t, "用户名或密码错误", status.Convert(err).Message())
  200. }
  201. // TC-0202: 密码错误
  202. func TestLogin_WrongPassword(t *testing.T) {
  203. ctx := context.Background()
  204. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  205. conn := testutil.GetTestSqlConn()
  206. now := time.Now().Unix()
  207. uid := testutil.UniqueId()
  208. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  209. Username: uid, Password: testutil.HashPassword("correct_pass"), Nickname: "nick",
  210. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  211. Status: 1, CreateTime: now, UpdateTime: now,
  212. })
  213. require.NoError(t, err)
  214. uId, _ := uRes.LastInsertId()
  215. t.Cleanup(func() {
  216. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  217. })
  218. srv := NewPermServer(svcCtx)
  219. _, err = srv.Login(ctx, &pb.LoginReq{
  220. Username: uid,
  221. Password: "wrong_pass",
  222. ProductCode: "any_product",
  223. })
  224. require.Error(t, err)
  225. assert.Equal(t, codes.Unauthenticated, status.Code(err))
  226. assert.Equal(t, "用户名或密码错误", status.Convert(err).Message())
  227. }
  228. // TC-0203: 账号冻结
  229. func TestLogin_AccountFrozen(t *testing.T) {
  230. ctx := context.Background()
  231. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  232. conn := testutil.GetTestSqlConn()
  233. now := time.Now().Unix()
  234. uid := testutil.UniqueId()
  235. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  236. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  237. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  238. Status: 2, CreateTime: now, UpdateTime: now,
  239. })
  240. require.NoError(t, err)
  241. uId, _ := uRes.LastInsertId()
  242. t.Cleanup(func() {
  243. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  244. })
  245. srv := NewPermServer(svcCtx)
  246. _, err = srv.Login(ctx, &pb.LoginReq{
  247. Username: uid,
  248. Password: "pass123",
  249. ProductCode: "any_product",
  250. })
  251. require.Error(t, err)
  252. assert.Equal(t, codes.PermissionDenied, status.Code(err))
  253. assert.Equal(t, "账号已被冻结", status.Convert(err).Message())
  254. }
  255. // TC-0204: 超管被拒绝
  256. func TestLogin_SuperAdminRejected(t *testing.T) {
  257. ctx := context.Background()
  258. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  259. conn := testutil.GetTestSqlConn()
  260. now := time.Now().Unix()
  261. uid := testutil.UniqueId()
  262. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  263. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "sa",
  264. Avatar: sql.NullString{}, IsSuperAdmin: 1, MustChangePassword: 2,
  265. Status: 1, CreateTime: now, UpdateTime: now,
  266. })
  267. require.NoError(t, err)
  268. uId, _ := uRes.LastInsertId()
  269. t.Cleanup(func() {
  270. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  271. })
  272. srv := NewPermServer(svcCtx)
  273. _, err = srv.Login(ctx, &pb.LoginReq{
  274. Username: uid,
  275. Password: "pass123",
  276. ProductCode: "any_product",
  277. })
  278. require.Error(t, err)
  279. assert.Equal(t, codes.PermissionDenied, status.Code(err))
  280. assert.Equal(t, "超级管理员不允许通过产品端登录,请使用管理后台", status.Convert(err).Message())
  281. }
  282. // TC-0205: 普通用户+productCode
  283. func TestLogin_NormalUserWithProductCode(t *testing.T) {
  284. ctx := context.Background()
  285. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  286. conn := testutil.GetTestSqlConn()
  287. now := time.Now().Unix()
  288. uid := testutil.UniqueId()
  289. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  290. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  291. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  292. Status: 1, CreateTime: now, UpdateTime: now,
  293. })
  294. require.NoError(t, err)
  295. uId, _ := uRes.LastInsertId()
  296. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  297. Code: uid, Name: "test_prod", AppKey: uid + "_k", AppSecret: "s1",
  298. Status: 1, CreateTime: now, UpdateTime: now,
  299. })
  300. require.NoError(t, err)
  301. pId, _ := pRes.LastInsertId()
  302. mbrRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  303. ProductCode: uid, UserId: uId, MemberType: "MEMBER",
  304. Status: 1, CreateTime: now, UpdateTime: now,
  305. })
  306. require.NoError(t, err)
  307. mbrId, _ := mbrRes.LastInsertId()
  308. roleRes, err := svcCtx.SysRoleModel.Insert(ctx, &roleModel.SysRole{
  309. ProductCode: uid, Name: uid + "_role", Status: 1, PermsLevel: 1,
  310. CreateTime: now, UpdateTime: now,
  311. })
  312. require.NoError(t, err)
  313. roleId, _ := roleRes.LastInsertId()
  314. pm1Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  315. ProductCode: uid, Name: "p1", Code: uid + "_c1",
  316. Status: 1, CreateTime: now, UpdateTime: now,
  317. })
  318. require.NoError(t, err)
  319. pm1Id, _ := pm1Res.LastInsertId()
  320. urRes, err := svcCtx.SysUserRoleModel.Insert(ctx, &userRoleModel.SysUserRole{
  321. UserId: uId, RoleId: roleId, CreateTime: now, UpdateTime: now,
  322. })
  323. require.NoError(t, err)
  324. urId, _ := urRes.LastInsertId()
  325. rpRes, err := svcCtx.SysRolePermModel.Insert(ctx, &rolePermModel.SysRolePerm{
  326. RoleId: roleId, PermId: pm1Id, CreateTime: now, UpdateTime: now,
  327. })
  328. require.NoError(t, err)
  329. rpId, _ := rpRes.LastInsertId()
  330. t.Cleanup(func() {
  331. testutil.CleanTable(ctx, conn, "`sys_role_perm`", rpId)
  332. testutil.CleanTable(ctx, conn, "`sys_user_role`", urId)
  333. testutil.CleanTable(ctx, conn, "`sys_perm`", pm1Id)
  334. testutil.CleanTable(ctx, conn, "`sys_role`", roleId)
  335. testutil.CleanTable(ctx, conn, "`sys_product_member`", mbrId)
  336. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  337. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  338. })
  339. srv := NewPermServer(svcCtx)
  340. resp, err := srv.Login(ctx, &pb.LoginReq{
  341. Username: uid,
  342. Password: "pass123",
  343. ProductCode: uid,
  344. })
  345. require.NoError(t, err)
  346. assert.Equal(t, "MEMBER", resp.MemberType)
  347. assert.Contains(t, resp.Perms, uid+"_c1")
  348. assert.NotEmpty(t, resp.AccessToken)
  349. assert.NotEmpty(t, resp.RefreshToken)
  350. }
  351. // TC-0207: productCode为空
  352. func TestLogin_EmptyProductCode(t *testing.T) {
  353. ctx := context.Background()
  354. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  355. srv := NewPermServer(svcCtx)
  356. _, err := srv.Login(ctx, &pb.LoginReq{
  357. Username: "anyuser",
  358. Password: "anypass",
  359. ProductCode: "",
  360. })
  361. require.Error(t, err)
  362. assert.Equal(t, codes.InvalidArgument, status.Code(err))
  363. assert.Equal(t, "productCode不能为空", status.Convert(err).Message())
  364. }
  365. // ---------- RefreshToken ----------
  366. // TC-0208: 正常刷新(refreshToken原样返回,不重新生成)
  367. func TestRefreshToken_Normal(t *testing.T) {
  368. ctx := context.Background()
  369. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  370. conn := testutil.GetTestSqlConn()
  371. now := time.Now().Unix()
  372. uid := testutil.UniqueId()
  373. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  374. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  375. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  376. Status: 1, CreateTime: now, UpdateTime: now,
  377. })
  378. require.NoError(t, err)
  379. uId, _ := uRes.LastInsertId()
  380. t.Cleanup(func() {
  381. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  382. })
  383. cfg := testutil.GetTestConfig()
  384. refreshToken, err := authHelper.GenerateRefreshToken(cfg.Auth.RefreshSecret, cfg.Auth.RefreshExpire, uId, "", 0)
  385. require.NoError(t, err)
  386. srv := NewPermServer(svcCtx)
  387. resp, err := srv.RefreshToken(ctx, &pb.RefreshTokenReq{
  388. RefreshToken: refreshToken,
  389. })
  390. require.NoError(t, err)
  391. assert.NotEmpty(t, resp.AccessToken)
  392. assert.Equal(t, refreshToken, resp.RefreshToken, "refreshToken应原样返回,不重新生成")
  393. assert.True(t, resp.Expires > time.Now().Unix(), "expires应为未来的unix时间戳")
  394. }
  395. // TC-0209: token无效
  396. func TestRefreshToken_InvalidToken(t *testing.T) {
  397. ctx := context.Background()
  398. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  399. srv := NewPermServer(svcCtx)
  400. _, err := srv.RefreshToken(ctx, &pb.RefreshTokenReq{
  401. RefreshToken: "invalid.token.string",
  402. })
  403. require.Error(t, err)
  404. assert.Equal(t, codes.Unauthenticated, status.Code(err))
  405. assert.Equal(t, "refreshToken无效或已过期", status.Convert(err).Message())
  406. }
  407. // TC-0210: 账号冻结
  408. func TestRefreshToken_AccountFrozen(t *testing.T) {
  409. ctx := context.Background()
  410. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  411. conn := testutil.GetTestSqlConn()
  412. now := time.Now().Unix()
  413. uid := testutil.UniqueId()
  414. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  415. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  416. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  417. Status: 2, CreateTime: now, UpdateTime: now,
  418. })
  419. require.NoError(t, err)
  420. uId, _ := uRes.LastInsertId()
  421. t.Cleanup(func() {
  422. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  423. })
  424. cfg := testutil.GetTestConfig()
  425. refreshToken, err := authHelper.GenerateRefreshToken(cfg.Auth.RefreshSecret, cfg.Auth.RefreshExpire, uId, "", 0)
  426. require.NoError(t, err)
  427. srv := NewPermServer(svcCtx)
  428. _, err = srv.RefreshToken(ctx, &pb.RefreshTokenReq{
  429. RefreshToken: refreshToken,
  430. })
  431. require.Error(t, err)
  432. assert.Equal(t, codes.PermissionDenied, status.Code(err))
  433. assert.Equal(t, "账号已被冻结", status.Convert(err).Message())
  434. }
  435. // TC-0211: productCode回退到claims
  436. func TestRefreshToken_FallbackToClaimsProductCode(t *testing.T) {
  437. ctx := context.Background()
  438. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  439. conn := testutil.GetTestSqlConn()
  440. now := time.Now().Unix()
  441. uid := testutil.UniqueId()
  442. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  443. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  444. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  445. Status: 1, CreateTime: now, UpdateTime: now,
  446. })
  447. require.NoError(t, err)
  448. uId, _ := uRes.LastInsertId()
  449. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  450. Code: uid, Name: "test_prod", AppKey: uid + "_k", AppSecret: "s1",
  451. Status: 1, CreateTime: now, UpdateTime: now,
  452. })
  453. require.NoError(t, err)
  454. pId, _ := pRes.LastInsertId()
  455. mbrRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  456. ProductCode: uid, UserId: uId, MemberType: "MEMBER",
  457. Status: 1, CreateTime: now, UpdateTime: now,
  458. })
  459. require.NoError(t, err)
  460. mbrId, _ := mbrRes.LastInsertId()
  461. t.Cleanup(func() {
  462. testutil.CleanTable(ctx, conn, "`sys_product_member`", mbrId)
  463. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  464. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  465. })
  466. cfg := testutil.GetTestConfig()
  467. refreshToken, err := authHelper.GenerateRefreshToken(cfg.Auth.RefreshSecret, cfg.Auth.RefreshExpire, uId, uid, 0)
  468. require.NoError(t, err)
  469. srv := NewPermServer(svcCtx)
  470. resp, err := srv.RefreshToken(ctx, &pb.RefreshTokenReq{
  471. RefreshToken: refreshToken,
  472. ProductCode: "",
  473. })
  474. require.NoError(t, err)
  475. assert.NotEmpty(t, resp.AccessToken)
  476. assert.Equal(t, refreshToken, resp.RefreshToken, "refreshToken应原样返回")
  477. }
  478. // TC-0212: 超管+productCode
  479. func TestRefreshToken_SuperAdminWithProductCode(t *testing.T) {
  480. ctx := context.Background()
  481. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  482. conn := testutil.GetTestSqlConn()
  483. now := time.Now().Unix()
  484. uid := testutil.UniqueId()
  485. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  486. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "sa",
  487. Avatar: sql.NullString{}, IsSuperAdmin: 1, MustChangePassword: 2,
  488. Status: 1, CreateTime: now, UpdateTime: now,
  489. })
  490. require.NoError(t, err)
  491. uId, _ := uRes.LastInsertId()
  492. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  493. Code: uid, Name: "test_prod", AppKey: uid + "_k", AppSecret: "s1",
  494. Status: 1, CreateTime: now, UpdateTime: now,
  495. })
  496. require.NoError(t, err)
  497. pId, _ := pRes.LastInsertId()
  498. pm1Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  499. ProductCode: uid, Name: "p1", Code: uid + "_c1",
  500. Status: 1, CreateTime: now, UpdateTime: now,
  501. })
  502. require.NoError(t, err)
  503. pm1Id, _ := pm1Res.LastInsertId()
  504. t.Cleanup(func() {
  505. testutil.CleanTable(ctx, conn, "`sys_perm`", pm1Id)
  506. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  507. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  508. })
  509. cfg := testutil.GetTestConfig()
  510. refreshToken, err := authHelper.GenerateRefreshToken(cfg.Auth.RefreshSecret, cfg.Auth.RefreshExpire, uId, uid, 0)
  511. require.NoError(t, err)
  512. srv := NewPermServer(svcCtx)
  513. resp, err := srv.RefreshToken(ctx, &pb.RefreshTokenReq{
  514. RefreshToken: refreshToken,
  515. ProductCode: uid,
  516. })
  517. require.NoError(t, err)
  518. assert.NotEmpty(t, resp.AccessToken)
  519. assert.Equal(t, refreshToken, resp.RefreshToken, "refreshToken应原样返回")
  520. }
  521. // TC-0213: 普通用户+productCode
  522. func TestRefreshToken_NormalUserWithProductCode(t *testing.T) {
  523. ctx := context.Background()
  524. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  525. conn := testutil.GetTestSqlConn()
  526. now := time.Now().Unix()
  527. uid := testutil.UniqueId()
  528. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  529. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  530. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  531. Status: 1, CreateTime: now, UpdateTime: now,
  532. })
  533. require.NoError(t, err)
  534. uId, _ := uRes.LastInsertId()
  535. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  536. Code: uid, Name: "test_prod", AppKey: uid + "_k", AppSecret: "s1",
  537. Status: 1, CreateTime: now, UpdateTime: now,
  538. })
  539. require.NoError(t, err)
  540. pId, _ := pRes.LastInsertId()
  541. mbrRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  542. ProductCode: uid, UserId: uId, MemberType: "MEMBER",
  543. Status: 1, CreateTime: now, UpdateTime: now,
  544. })
  545. require.NoError(t, err)
  546. mbrId, _ := mbrRes.LastInsertId()
  547. pm1Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  548. ProductCode: uid, Name: "p1", Code: uid + "_c1",
  549. Status: 1, CreateTime: now, UpdateTime: now,
  550. })
  551. require.NoError(t, err)
  552. pm1Id, _ := pm1Res.LastInsertId()
  553. roleRes, err := svcCtx.SysRoleModel.Insert(ctx, &roleModel.SysRole{
  554. ProductCode: uid, Name: uid + "_role", Status: 1, PermsLevel: 1,
  555. CreateTime: now, UpdateTime: now,
  556. })
  557. require.NoError(t, err)
  558. roleId, _ := roleRes.LastInsertId()
  559. urRes, err := svcCtx.SysUserRoleModel.Insert(ctx, &userRoleModel.SysUserRole{
  560. UserId: uId, RoleId: roleId, CreateTime: now, UpdateTime: now,
  561. })
  562. require.NoError(t, err)
  563. urId, _ := urRes.LastInsertId()
  564. rpRes, err := svcCtx.SysRolePermModel.Insert(ctx, &rolePermModel.SysRolePerm{
  565. RoleId: roleId, PermId: pm1Id, CreateTime: now, UpdateTime: now,
  566. })
  567. require.NoError(t, err)
  568. rpId, _ := rpRes.LastInsertId()
  569. t.Cleanup(func() {
  570. testutil.CleanTable(ctx, conn, "`sys_role_perm`", rpId)
  571. testutil.CleanTable(ctx, conn, "`sys_user_role`", urId)
  572. testutil.CleanTable(ctx, conn, "`sys_perm`", pm1Id)
  573. testutil.CleanTable(ctx, conn, "`sys_role`", roleId)
  574. testutil.CleanTable(ctx, conn, "`sys_product_member`", mbrId)
  575. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  576. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  577. })
  578. cfg := testutil.GetTestConfig()
  579. refreshToken, err := authHelper.GenerateRefreshToken(cfg.Auth.RefreshSecret, cfg.Auth.RefreshExpire, uId, uid, 0)
  580. require.NoError(t, err)
  581. srv := NewPermServer(svcCtx)
  582. resp, err := srv.RefreshToken(ctx, &pb.RefreshTokenReq{
  583. RefreshToken: refreshToken,
  584. ProductCode: uid,
  585. })
  586. require.NoError(t, err)
  587. assert.NotEmpty(t, resp.AccessToken)
  588. assert.Equal(t, refreshToken, resp.RefreshToken, "refreshToken应原样返回")
  589. }
  590. // ---------- VerifyToken ----------
  591. // TC-0214: 有效token(VerifyToken 现在实时查询DB,需要真实数据)
  592. func TestVerifyToken_Valid(t *testing.T) {
  593. ctx := context.Background()
  594. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  595. cfg := testutil.GetTestConfig()
  596. conn := testutil.GetTestSqlConn()
  597. ts := time.Now().Unix()
  598. uid := testutil.UniqueId()
  599. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  600. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick_verify",
  601. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  602. Status: 1, CreateTime: ts, UpdateTime: ts,
  603. })
  604. require.NoError(t, err)
  605. uId, _ := uRes.LastInsertId()
  606. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  607. Code: uid, Name: "prod_verify", AppKey: uid + "_k", AppSecret: "s1",
  608. Status: 1, CreateTime: ts, UpdateTime: ts,
  609. })
  610. require.NoError(t, err)
  611. pId, _ := pRes.LastInsertId()
  612. pmRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  613. ProductCode: uid, UserId: uId, MemberType: "ADMIN", Status: 1,
  614. CreateTime: ts, UpdateTime: ts,
  615. })
  616. require.NoError(t, err)
  617. pmId, _ := pmRes.LastInsertId()
  618. pm1Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  619. ProductCode: uid, Name: "perm_a", Code: "perm_a",
  620. Status: 1, CreateTime: ts, UpdateTime: ts,
  621. })
  622. require.NoError(t, err)
  623. pm1Id, _ := pm1Res.LastInsertId()
  624. pm2Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  625. ProductCode: uid, Name: "perm_b", Code: "perm_b",
  626. Status: 1, CreateTime: ts, UpdateTime: ts,
  627. })
  628. require.NoError(t, err)
  629. pm2Id, _ := pm2Res.LastInsertId()
  630. t.Cleanup(func() {
  631. svcCtx.UserDetailsLoader.Del(ctx, uId, uid)
  632. testutil.CleanTable(ctx, conn, "`sys_perm`", pm1Id, pm2Id)
  633. testutil.CleanTable(ctx, conn, "`sys_product_member`", pmId)
  634. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  635. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  636. })
  637. svcCtx.UserDetailsLoader.Del(ctx, uId, uid)
  638. accessToken, err := authHelper.GenerateAccessToken(
  639. cfg.Auth.AccessSecret, cfg.Auth.AccessExpire,
  640. uId, uid, uid, "ADMIN", 0,
  641. )
  642. require.NoError(t, err)
  643. srv := NewPermServer(svcCtx)
  644. resp, err := srv.VerifyToken(ctx, &pb.VerifyTokenReq{AccessToken: accessToken})
  645. require.NoError(t, err)
  646. assert.True(t, resp.Valid)
  647. assert.Equal(t, uId, resp.UserId)
  648. assert.Equal(t, uid, resp.Username)
  649. assert.Equal(t, "ADMIN", resp.MemberType)
  650. assert.ElementsMatch(t, []string{"perm_a", "perm_b"}, resp.Perms)
  651. }
  652. // TC-0215: 无效token
  653. func TestVerifyToken_Invalid(t *testing.T) {
  654. ctx := context.Background()
  655. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  656. srv := NewPermServer(svcCtx)
  657. resp, err := srv.VerifyToken(ctx, &pb.VerifyTokenReq{AccessToken: "invalid.token.here"})
  658. require.NoError(t, err)
  659. assert.False(t, resp.Valid)
  660. }
  661. // TC-0216: 缺少userId
  662. func TestVerifyToken_MissingUserId(t *testing.T) {
  663. ctx := context.Background()
  664. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  665. cfg := testutil.GetTestConfig()
  666. // Generate a token without userId by using raw JWT
  667. token := createTokenWithoutUserId(cfg.Auth.AccessSecret)
  668. srv := NewPermServer(svcCtx)
  669. resp, err := srv.VerifyToken(ctx, &pb.VerifyTokenReq{AccessToken: token})
  670. require.NoError(t, err)
  671. assert.False(t, resp.Valid)
  672. }
  673. // ---------- GetUserPerms ----------
  674. // TC-0220: 用户不存在
  675. func TestGetUserPerms_UserNotFound(t *testing.T) {
  676. ctx := context.Background()
  677. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  678. srv := NewPermServer(svcCtx)
  679. _, err := srv.GetUserPerms(ctx, &pb.GetUserPermsReq{
  680. UserId: 999999999,
  681. ProductCode: "any_product",
  682. })
  683. require.Error(t, err)
  684. assert.Equal(t, codes.NotFound, status.Code(err))
  685. assert.Equal(t, "用户不存在", status.Convert(err).Message())
  686. }
  687. // TC-0221: 超管
  688. func TestGetUserPerms_SuperAdmin(t *testing.T) {
  689. ctx := context.Background()
  690. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  691. conn := testutil.GetTestSqlConn()
  692. now := time.Now().Unix()
  693. uid := testutil.UniqueId()
  694. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  695. Username: uid, Password: testutil.HashPassword("pass"), Nickname: "sa",
  696. Avatar: sql.NullString{}, IsSuperAdmin: 1, MustChangePassword: 2,
  697. Status: 1, CreateTime: now, UpdateTime: now,
  698. })
  699. require.NoError(t, err)
  700. uId, _ := uRes.LastInsertId()
  701. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  702. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: "s1",
  703. Status: 1, CreateTime: now, UpdateTime: now,
  704. })
  705. require.NoError(t, err)
  706. pId, _ := pRes.LastInsertId()
  707. pm1Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  708. ProductCode: uid, Name: "p1", Code: uid + "_c1",
  709. Status: 1, CreateTime: now, UpdateTime: now,
  710. })
  711. require.NoError(t, err)
  712. pm1Id, _ := pm1Res.LastInsertId()
  713. mRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  714. ProductCode: uid, UserId: uId, MemberType: "ADMIN",
  715. Status: 1, CreateTime: now, UpdateTime: now,
  716. })
  717. require.NoError(t, err)
  718. mId, _ := mRes.LastInsertId()
  719. t.Cleanup(func() {
  720. testutil.CleanTable(ctx, conn, "`sys_product_member`", mId)
  721. testutil.CleanTable(ctx, conn, "`sys_perm`", pm1Id)
  722. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  723. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  724. })
  725. srv := NewPermServer(svcCtx)
  726. resp, err := srv.GetUserPerms(ctx, &pb.GetUserPermsReq{
  727. UserId: uId,
  728. ProductCode: uid,
  729. })
  730. require.NoError(t, err)
  731. assert.Equal(t, "SUPER_ADMIN", resp.MemberType)
  732. assert.Contains(t, resp.Perms, uid+"_c1")
  733. }
  734. // TC-0199: 验证disabled计数
  735. func TestSyncPermissions_VerifyDisabledCount(t *testing.T) {
  736. ctx := context.Background()
  737. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  738. conn := testutil.GetTestSqlConn()
  739. now := time.Now().Unix()
  740. uid := testutil.UniqueId()
  741. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  742. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: bcryptHash(t, "secret1"),
  743. Status: 1, CreateTime: now, UpdateTime: now,
  744. })
  745. require.NoError(t, err)
  746. pId, _ := pRes.LastInsertId()
  747. var permIds []int64
  748. for i := 0; i < 5; i++ {
  749. pmRes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  750. ProductCode: uid, Name: "p", Code: fmt.Sprintf("%s_c%d", uid, i),
  751. Status: 1, CreateTime: now, UpdateTime: now,
  752. })
  753. require.NoError(t, err)
  754. pmId, _ := pmRes.LastInsertId()
  755. permIds = append(permIds, pmId)
  756. }
  757. t.Cleanup(func() {
  758. testutil.CleanTable(ctx, conn, "`sys_perm`", permIds...)
  759. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  760. })
  761. srv := NewPermServer(svcCtx)
  762. resp, err := srv.SyncPermissions(ctx, &pb.SyncPermissionsReq{
  763. AppKey: uid,
  764. AppSecret: "secret1",
  765. Perms: []*pb.PermItem{
  766. {Code: fmt.Sprintf("%s_c0", uid), Name: "p"},
  767. {Code: fmt.Sprintf("%s_c1", uid), Name: "p"},
  768. },
  769. })
  770. require.NoError(t, err)
  771. assert.Equal(t, int64(3), resp.Disabled)
  772. }
  773. // TC-0222: MEMBER-DENY覆盖
  774. func TestGetUserPerms_MemberDENYOverride(t *testing.T) {
  775. ctx := context.Background()
  776. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  777. conn := testutil.GetTestSqlConn()
  778. now := time.Now().Unix()
  779. uid := testutil.UniqueId()
  780. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  781. Username: uid, Password: testutil.HashPassword("pass"), Nickname: "nick",
  782. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  783. Status: 1, CreateTime: now, UpdateTime: now,
  784. })
  785. require.NoError(t, err)
  786. uId, _ := uRes.LastInsertId()
  787. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  788. Code: uid, Name: "test_prod", AppKey: uid + "_k", AppSecret: "s1",
  789. Status: 1, CreateTime: now, UpdateTime: now,
  790. })
  791. require.NoError(t, err)
  792. pId, _ := pRes.LastInsertId()
  793. mbrRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  794. ProductCode: uid, UserId: uId, MemberType: "MEMBER",
  795. Status: 1, CreateTime: now, UpdateTime: now,
  796. })
  797. require.NoError(t, err)
  798. mbrId, _ := mbrRes.LastInsertId()
  799. roleRes, err := svcCtx.SysRoleModel.Insert(ctx, &roleModel.SysRole{
  800. ProductCode: uid, Name: uid + "_role", Status: 1, PermsLevel: 1,
  801. CreateTime: now, UpdateTime: now,
  802. })
  803. require.NoError(t, err)
  804. roleId, _ := roleRes.LastInsertId()
  805. permARes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  806. ProductCode: uid, Name: "permA", Code: uid + "_pA",
  807. Status: 1, CreateTime: now, UpdateTime: now,
  808. })
  809. require.NoError(t, err)
  810. permAId, _ := permARes.LastInsertId()
  811. permBRes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  812. ProductCode: uid, Name: "permB", Code: uid + "_pB",
  813. Status: 1, CreateTime: now, UpdateTime: now,
  814. })
  815. require.NoError(t, err)
  816. permBId, _ := permBRes.LastInsertId()
  817. urRes, err := svcCtx.SysUserRoleModel.Insert(ctx, &userRoleModel.SysUserRole{
  818. UserId: uId, RoleId: roleId, CreateTime: now, UpdateTime: now,
  819. })
  820. require.NoError(t, err)
  821. urId, _ := urRes.LastInsertId()
  822. rpARes, err := svcCtx.SysRolePermModel.Insert(ctx, &rolePermModel.SysRolePerm{
  823. RoleId: roleId, PermId: permAId, CreateTime: now, UpdateTime: now,
  824. })
  825. require.NoError(t, err)
  826. rpAId, _ := rpARes.LastInsertId()
  827. rpBRes, err := svcCtx.SysRolePermModel.Insert(ctx, &rolePermModel.SysRolePerm{
  828. RoleId: roleId, PermId: permBId, CreateTime: now, UpdateTime: now,
  829. })
  830. require.NoError(t, err)
  831. rpBId, _ := rpBRes.LastInsertId()
  832. upRes, err := svcCtx.SysUserPermModel.Insert(ctx, &userPermModel.SysUserPerm{
  833. UserId: uId, PermId: permAId, Effect: "DENY",
  834. CreateTime: now, UpdateTime: now,
  835. })
  836. require.NoError(t, err)
  837. upId, _ := upRes.LastInsertId()
  838. t.Cleanup(func() {
  839. testutil.CleanTable(ctx, conn, "`sys_user_perm`", upId)
  840. testutil.CleanTable(ctx, conn, "`sys_role_perm`", rpAId, rpBId)
  841. testutil.CleanTable(ctx, conn, "`sys_user_role`", urId)
  842. testutil.CleanTable(ctx, conn, "`sys_perm`", permAId, permBId)
  843. testutil.CleanTable(ctx, conn, "`sys_role`", roleId)
  844. testutil.CleanTable(ctx, conn, "`sys_product_member`", mbrId)
  845. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  846. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  847. })
  848. srv := NewPermServer(svcCtx)
  849. resp, err := srv.GetUserPerms(ctx, &pb.GetUserPermsReq{
  850. UserId: uId,
  851. ProductCode: uid,
  852. })
  853. require.NoError(t, err)
  854. assert.Equal(t, "MEMBER", resp.MemberType)
  855. assert.Contains(t, resp.Perms, uid+"_pB")
  856. assert.NotContains(t, resp.Perms, uid+"_pA")
  857. }
  858. // TC-0217: gRPC VerifyToken 用户已冻结返回valid=false(H-4修复验证)
  859. func TestVerifyToken_FrozenUserReturnsInvalid(t *testing.T) {
  860. ctx := context.Background()
  861. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  862. conn := testutil.GetTestSqlConn()
  863. now := time.Now().Unix()
  864. uid := testutil.UniqueId()
  865. cfg := testutil.GetTestConfig()
  866. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  867. Username: uid, Password: testutil.HashPassword("pass"), Nickname: "frozen",
  868. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  869. Status: 2, CreateTime: now, UpdateTime: now,
  870. })
  871. require.NoError(t, err)
  872. uId, _ := uRes.LastInsertId()
  873. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_user`", uId) })
  874. accessToken, err := authHelper.GenerateAccessToken(
  875. cfg.Auth.AccessSecret, cfg.Auth.AccessExpire,
  876. uId, uid, "", "MEMBER", 0,
  877. )
  878. require.NoError(t, err)
  879. srv := NewPermServer(svcCtx)
  880. resp, err := srv.VerifyToken(ctx, &pb.VerifyTokenReq{AccessToken: accessToken})
  881. require.NoError(t, err)
  882. assert.False(t, resp.Valid, "frozen user token should be invalid")
  883. }
  884. // TC-0218: gRPC VerifyToken 非产品成员返回valid=false(H-4修复验证)
  885. func TestVerifyToken_NonMemberReturnsInvalid(t *testing.T) {
  886. ctx := context.Background()
  887. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  888. conn := testutil.GetTestSqlConn()
  889. now := time.Now().Unix()
  890. uid := testutil.UniqueId()
  891. pc := testutil.UniqueId()
  892. cfg := testutil.GetTestConfig()
  893. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  894. Username: uid, Password: testutil.HashPassword("pass"), Nickname: "user",
  895. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  896. Status: 1, CreateTime: now, UpdateTime: now,
  897. })
  898. require.NoError(t, err)
  899. uId, _ := uRes.LastInsertId()
  900. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  901. Code: pc, Name: "prod", AppKey: testutil.UniqueId(), AppSecret: "s",
  902. Status: 1, CreateTime: now, UpdateTime: now,
  903. })
  904. require.NoError(t, err)
  905. pId, _ := pRes.LastInsertId()
  906. t.Cleanup(func() {
  907. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  908. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  909. })
  910. accessToken, err := authHelper.GenerateAccessToken(
  911. cfg.Auth.AccessSecret, cfg.Auth.AccessExpire,
  912. uId, uid, pc, "MEMBER", 0,
  913. )
  914. require.NoError(t, err)
  915. srv := NewPermServer(svcCtx)
  916. resp, err := srv.VerifyToken(ctx, &pb.VerifyTokenReq{AccessToken: accessToken})
  917. require.NoError(t, err)
  918. assert.False(t, resp.Valid, "non-member user with productCode should be invalid")
  919. }
  920. // TC-0219: gRPC VerifyToken 返回实时权限和成员类型(H-4修复验证)
  921. func TestVerifyToken_ReturnsRealtimeData(t *testing.T) {
  922. ctx := context.Background()
  923. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  924. conn := testutil.GetTestSqlConn()
  925. now := time.Now().Unix()
  926. uid := 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: uid, Name: "prod", AppKey: uid + "_k", AppSecret: "s",
  937. Status: 1, CreateTime: now, UpdateTime: now,
  938. })
  939. require.NoError(t, err)
  940. pId, _ := pRes.LastInsertId()
  941. mbrRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  942. ProductCode: uid, UserId: uId, MemberType: "ADMIN",
  943. Status: 1, CreateTime: now, UpdateTime: now,
  944. })
  945. require.NoError(t, err)
  946. mbrId, _ := mbrRes.LastInsertId()
  947. permRes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  948. ProductCode: uid, Name: "realtime_perm", Code: uid + "_rt",
  949. Status: 1, CreateTime: now, UpdateTime: now,
  950. })
  951. require.NoError(t, err)
  952. permId, _ := permRes.LastInsertId()
  953. t.Cleanup(func() {
  954. testutil.CleanTable(ctx, conn, "`sys_perm`", permId)
  955. testutil.CleanTable(ctx, conn, "`sys_product_member`", mbrId)
  956. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  957. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  958. })
  959. accessToken, err := authHelper.GenerateAccessToken(
  960. cfg.Auth.AccessSecret, cfg.Auth.AccessExpire,
  961. uId, uid, uid, "MEMBER", 0,
  962. )
  963. require.NoError(t, err)
  964. svcCtx.UserDetailsLoader.Clean(ctx, uId)
  965. srv := NewPermServer(svcCtx)
  966. resp, err := srv.VerifyToken(ctx, &pb.VerifyTokenReq{AccessToken: accessToken})
  967. require.NoError(t, err)
  968. assert.True(t, resp.Valid)
  969. assert.Equal(t, "ADMIN", resp.MemberType, "should return realtime memberType, not token's")
  970. assert.Contains(t, resp.Perms, uid+"_rt", "should return realtime perms")
  971. }
  972. // TC-0206: gRPC Login 产品成员被禁用时拒绝(H-3修复验证)
  973. func TestLogin_DisabledMemberRejected(t *testing.T) {
  974. ctx := context.Background()
  975. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  976. conn := testutil.GetTestSqlConn()
  977. now := time.Now().Unix()
  978. uid := testutil.UniqueId()
  979. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  980. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  981. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  982. Status: 1, CreateTime: now, UpdateTime: now,
  983. })
  984. require.NoError(t, err)
  985. uId, _ := uRes.LastInsertId()
  986. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  987. Code: uid, Name: "prod", AppKey: uid + "_k", AppSecret: "s1",
  988. Status: 1, CreateTime: now, UpdateTime: now,
  989. })
  990. require.NoError(t, err)
  991. pId, _ := pRes.LastInsertId()
  992. pmRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  993. ProductCode: uid, UserId: uId, MemberType: "MEMBER", Status: 2,
  994. CreateTime: now, UpdateTime: now,
  995. })
  996. require.NoError(t, err)
  997. pmId, _ := pmRes.LastInsertId()
  998. t.Cleanup(func() {
  999. testutil.CleanTable(ctx, conn, "`sys_product_member`", pmId)
  1000. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  1001. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  1002. })
  1003. srv := NewPermServer(svcCtx)
  1004. _, err = srv.Login(ctx, &pb.LoginReq{
  1005. Username: uid,
  1006. Password: "pass123",
  1007. ProductCode: uid,
  1008. })
  1009. require.Error(t, err)
  1010. assert.Equal(t, codes.PermissionDenied, status.Code(err))
  1011. assert.Equal(t, "您在该产品下的成员资格已被禁用", status.Convert(err).Message())
  1012. }
  1013. // helper: create a JWT with no userId claim
  1014. func createTokenWithoutUserId(secret string) string {
  1015. claims := jwt.MapClaims{
  1016. "username": "test",
  1017. "exp": time.Now().Add(time.Hour).Unix(),
  1018. }
  1019. token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
  1020. s, _ := token.SignedString([]byte(secret))
  1021. return s
  1022. }