permserver_test.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  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. "google.golang.org/grpc/codes"
  24. "google.golang.org/grpc/status"
  25. )
  26. // ---------- SyncPermissions ----------
  27. // TC-0161: 正常同步
  28. func TestSyncPermissions_Normal(t *testing.T) {
  29. ctx := context.Background()
  30. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  31. conn := testutil.GetTestSqlConn()
  32. now := time.Now().Unix()
  33. uid := testutil.UniqueId()
  34. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  35. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: "secret1",
  36. Status: 1, CreateTime: now, UpdateTime: now,
  37. })
  38. require.NoError(t, err)
  39. pId, _ := pRes.LastInsertId()
  40. t.Cleanup(func() {
  41. testutil.CleanTableByField(ctx, conn, "`sys_perm`", "productCode", uid)
  42. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  43. })
  44. srv := NewPermServer(svcCtx)
  45. resp, err := srv.SyncPermissions(ctx, &pb.SyncPermissionsReq{
  46. AppKey: uid,
  47. AppSecret: "secret1",
  48. Perms: []*pb.PermItem{
  49. {Code: "perm_a", Name: "Perm A", Remark: "remark_a"},
  50. {Code: "perm_b", Name: "Perm B", Remark: "remark_b"},
  51. },
  52. })
  53. require.NoError(t, err)
  54. assert.Equal(t, int64(2), resp.Added)
  55. assert.Equal(t, int64(0), resp.Updated)
  56. assert.Equal(t, int64(0), resp.Disabled)
  57. resp2, err := srv.SyncPermissions(ctx, &pb.SyncPermissionsReq{
  58. AppKey: uid,
  59. AppSecret: "secret1",
  60. Perms: []*pb.PermItem{
  61. {Code: "perm_a", Name: "Perm A Updated", Remark: "remark_a"},
  62. },
  63. })
  64. require.NoError(t, err)
  65. assert.Equal(t, int64(0), resp2.Added)
  66. assert.Equal(t, int64(1), resp2.Updated)
  67. assert.Equal(t, int64(1), resp2.Disabled)
  68. }
  69. // TC-0162: appKey无效
  70. func TestSyncPermissions_InvalidAppKey(t *testing.T) {
  71. ctx := context.Background()
  72. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  73. srv := NewPermServer(svcCtx)
  74. _, err := srv.SyncPermissions(ctx, &pb.SyncPermissionsReq{
  75. AppKey: "nonexistent_key",
  76. AppSecret: "any",
  77. Perms: []*pb.PermItem{{Code: "c", Name: "n"}},
  78. })
  79. require.Error(t, err)
  80. assert.Equal(t, codes.Unauthenticated, status.Code(err))
  81. assert.Equal(t, "无效的appKey", status.Convert(err).Message())
  82. }
  83. // TC-0163: appSecret错误
  84. func TestSyncPermissions_WrongAppSecret(t *testing.T) {
  85. ctx := context.Background()
  86. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  87. conn := testutil.GetTestSqlConn()
  88. now := time.Now().Unix()
  89. uid := testutil.UniqueId()
  90. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  91. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: "real_secret",
  92. Status: 1, CreateTime: now, UpdateTime: now,
  93. })
  94. require.NoError(t, err)
  95. pId, _ := pRes.LastInsertId()
  96. t.Cleanup(func() {
  97. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  98. })
  99. srv := NewPermServer(svcCtx)
  100. _, err = srv.SyncPermissions(ctx, &pb.SyncPermissionsReq{
  101. AppKey: uid,
  102. AppSecret: "wrong_secret",
  103. Perms: []*pb.PermItem{{Code: "c", Name: "n"}},
  104. })
  105. require.Error(t, err)
  106. assert.Equal(t, codes.Unauthenticated, status.Code(err))
  107. assert.Equal(t, "appSecret验证失败", status.Convert(err).Message())
  108. }
  109. // TC-0164: 产品已禁用
  110. func TestSyncPermissions_ProductDisabled(t *testing.T) {
  111. ctx := context.Background()
  112. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  113. conn := testutil.GetTestSqlConn()
  114. now := time.Now().Unix()
  115. uid := testutil.UniqueId()
  116. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  117. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: "secret1",
  118. Status: 2, CreateTime: now, UpdateTime: now,
  119. })
  120. require.NoError(t, err)
  121. pId, _ := pRes.LastInsertId()
  122. t.Cleanup(func() {
  123. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  124. })
  125. srv := NewPermServer(svcCtx)
  126. _, err = srv.SyncPermissions(ctx, &pb.SyncPermissionsReq{
  127. AppKey: uid,
  128. AppSecret: "secret1",
  129. Perms: []*pb.PermItem{{Code: "c", Name: "n"}},
  130. })
  131. require.Error(t, err)
  132. assert.Equal(t, codes.PermissionDenied, status.Code(err))
  133. assert.Equal(t, "产品已被禁用", status.Convert(err).Message())
  134. }
  135. // ---------- Login ----------
  136. // TC-0166: 正常登录(无productCode)
  137. func TestLogin_Normal(t *testing.T) {
  138. ctx := context.Background()
  139. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  140. conn := testutil.GetTestSqlConn()
  141. now := time.Now().Unix()
  142. uid := testutil.UniqueId()
  143. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  144. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  145. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  146. Status: 1, CreateTime: now, UpdateTime: now,
  147. })
  148. require.NoError(t, err)
  149. uId, _ := uRes.LastInsertId()
  150. t.Cleanup(func() {
  151. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  152. })
  153. srv := NewPermServer(svcCtx)
  154. resp, err := srv.Login(ctx, &pb.LoginReq{
  155. Username: uid,
  156. Password: "pass123",
  157. })
  158. require.NoError(t, err)
  159. assert.NotEmpty(t, resp.AccessToken)
  160. assert.NotEmpty(t, resp.RefreshToken)
  161. assert.True(t, resp.Expires > time.Now().Unix(), "expires应为未来的unix时间戳")
  162. assert.Equal(t, uId, resp.UserId)
  163. assert.Equal(t, uid, resp.Username)
  164. }
  165. // TC-0167: 用户不存在
  166. func TestLogin_UserNotFound(t *testing.T) {
  167. ctx := context.Background()
  168. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  169. srv := NewPermServer(svcCtx)
  170. _, err := srv.Login(ctx, &pb.LoginReq{
  171. Username: "nonexistent_user_xyz",
  172. Password: "any",
  173. })
  174. require.Error(t, err)
  175. assert.Equal(t, codes.Unauthenticated, status.Code(err))
  176. assert.Equal(t, "用户名或密码错误", status.Convert(err).Message())
  177. }
  178. // TC-0168: 密码错误
  179. func TestLogin_WrongPassword(t *testing.T) {
  180. ctx := context.Background()
  181. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  182. conn := testutil.GetTestSqlConn()
  183. now := time.Now().Unix()
  184. uid := testutil.UniqueId()
  185. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  186. Username: uid, Password: testutil.HashPassword("correct_pass"), Nickname: "nick",
  187. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  188. Status: 1, CreateTime: now, UpdateTime: now,
  189. })
  190. require.NoError(t, err)
  191. uId, _ := uRes.LastInsertId()
  192. t.Cleanup(func() {
  193. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  194. })
  195. srv := NewPermServer(svcCtx)
  196. _, err = srv.Login(ctx, &pb.LoginReq{
  197. Username: uid,
  198. Password: "wrong_pass",
  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-0169: 账号冻结
  205. func TestLogin_AccountFrozen(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("pass123"), Nickname: "nick",
  213. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  214. Status: 2, 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: "pass123",
  225. })
  226. require.Error(t, err)
  227. assert.Equal(t, codes.PermissionDenied, status.Code(err))
  228. assert.Equal(t, "账号已被冻结", status.Convert(err).Message())
  229. }
  230. // TC-0170: 超管+productCode
  231. func TestLogin_SuperAdminWithProductCode(t *testing.T) {
  232. ctx := context.Background()
  233. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  234. conn := testutil.GetTestSqlConn()
  235. now := time.Now().Unix()
  236. uid := testutil.UniqueId()
  237. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  238. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "sa",
  239. Avatar: sql.NullString{}, IsSuperAdmin: 1, MustChangePassword: 2,
  240. Status: 1, CreateTime: now, UpdateTime: now,
  241. })
  242. require.NoError(t, err)
  243. uId, _ := uRes.LastInsertId()
  244. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  245. Code: uid, Name: "test_prod", AppKey: uid + "_k", AppSecret: "s1",
  246. Status: 1, CreateTime: now, UpdateTime: now,
  247. })
  248. require.NoError(t, err)
  249. pId, _ := pRes.LastInsertId()
  250. pm1Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  251. ProductCode: uid, Name: "p1", Code: uid + "_c1",
  252. Status: 1, CreateTime: now, UpdateTime: now,
  253. })
  254. require.NoError(t, err)
  255. pm1Id, _ := pm1Res.LastInsertId()
  256. t.Cleanup(func() {
  257. testutil.CleanTable(ctx, conn, "`sys_perm`", pm1Id)
  258. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  259. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  260. })
  261. srv := NewPermServer(svcCtx)
  262. resp, err := srv.Login(ctx, &pb.LoginReq{
  263. Username: uid,
  264. Password: "pass123",
  265. ProductCode: uid,
  266. })
  267. require.NoError(t, err)
  268. assert.Equal(t, "SUPER_ADMIN", resp.MemberType)
  269. assert.Contains(t, resp.Perms, uid+"_c1")
  270. assert.NotEmpty(t, resp.AccessToken)
  271. assert.NotEmpty(t, resp.RefreshToken)
  272. }
  273. // TC-0171: 普通用户+productCode
  274. func TestLogin_NormalUserWithProductCode(t *testing.T) {
  275. ctx := context.Background()
  276. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  277. conn := testutil.GetTestSqlConn()
  278. now := time.Now().Unix()
  279. uid := testutil.UniqueId()
  280. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  281. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  282. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  283. Status: 1, CreateTime: now, UpdateTime: now,
  284. })
  285. require.NoError(t, err)
  286. uId, _ := uRes.LastInsertId()
  287. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  288. Code: uid, Name: "test_prod", AppKey: uid + "_k", AppSecret: "s1",
  289. Status: 1, CreateTime: now, UpdateTime: now,
  290. })
  291. require.NoError(t, err)
  292. pId, _ := pRes.LastInsertId()
  293. mbrRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  294. ProductCode: uid, UserId: uId, MemberType: "MEMBER",
  295. Status: 1, CreateTime: now, UpdateTime: now,
  296. })
  297. require.NoError(t, err)
  298. mbrId, _ := mbrRes.LastInsertId()
  299. roleRes, err := svcCtx.SysRoleModel.Insert(ctx, &roleModel.SysRole{
  300. ProductCode: uid, Name: uid + "_role", Status: 1, PermsLevel: 1,
  301. CreateTime: now, UpdateTime: now,
  302. })
  303. require.NoError(t, err)
  304. roleId, _ := roleRes.LastInsertId()
  305. pm1Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  306. ProductCode: uid, Name: "p1", Code: uid + "_c1",
  307. Status: 1, CreateTime: now, UpdateTime: now,
  308. })
  309. require.NoError(t, err)
  310. pm1Id, _ := pm1Res.LastInsertId()
  311. urRes, err := svcCtx.SysUserRoleModel.Insert(ctx, &userRoleModel.SysUserRole{
  312. UserId: uId, RoleId: roleId, CreateTime: now, UpdateTime: now,
  313. })
  314. require.NoError(t, err)
  315. urId, _ := urRes.LastInsertId()
  316. rpRes, err := svcCtx.SysRolePermModel.Insert(ctx, &rolePermModel.SysRolePerm{
  317. RoleId: roleId, PermId: pm1Id, CreateTime: now, UpdateTime: now,
  318. })
  319. require.NoError(t, err)
  320. rpId, _ := rpRes.LastInsertId()
  321. t.Cleanup(func() {
  322. testutil.CleanTable(ctx, conn, "`sys_role_perm`", rpId)
  323. testutil.CleanTable(ctx, conn, "`sys_user_role`", urId)
  324. testutil.CleanTable(ctx, conn, "`sys_perm`", pm1Id)
  325. testutil.CleanTable(ctx, conn, "`sys_role`", roleId)
  326. testutil.CleanTable(ctx, conn, "`sys_product_member`", mbrId)
  327. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  328. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  329. })
  330. srv := NewPermServer(svcCtx)
  331. resp, err := srv.Login(ctx, &pb.LoginReq{
  332. Username: uid,
  333. Password: "pass123",
  334. ProductCode: uid,
  335. })
  336. require.NoError(t, err)
  337. assert.Equal(t, "MEMBER", resp.MemberType)
  338. assert.Contains(t, resp.Perms, uid+"_c1")
  339. assert.NotEmpty(t, resp.AccessToken)
  340. assert.NotEmpty(t, resp.RefreshToken)
  341. }
  342. // ---------- RefreshToken ----------
  343. // TC-0172: 正常刷新(refreshToken原样返回,不重新生成)
  344. func TestRefreshToken_Normal(t *testing.T) {
  345. ctx := context.Background()
  346. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  347. conn := testutil.GetTestSqlConn()
  348. now := time.Now().Unix()
  349. uid := testutil.UniqueId()
  350. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  351. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  352. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  353. Status: 1, CreateTime: now, UpdateTime: now,
  354. })
  355. require.NoError(t, err)
  356. uId, _ := uRes.LastInsertId()
  357. t.Cleanup(func() {
  358. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  359. })
  360. cfg := testutil.GetTestConfig()
  361. refreshToken, err := authHelper.GenerateRefreshToken(cfg.Auth.RefreshSecret, cfg.Auth.RefreshExpire, uId, "")
  362. require.NoError(t, err)
  363. srv := NewPermServer(svcCtx)
  364. resp, err := srv.RefreshToken(ctx, &pb.RefreshTokenReq{
  365. RefreshToken: refreshToken,
  366. })
  367. require.NoError(t, err)
  368. assert.NotEmpty(t, resp.AccessToken)
  369. assert.Equal(t, refreshToken, resp.RefreshToken, "refreshToken应原样返回,不重新生成")
  370. assert.True(t, resp.Expires > time.Now().Unix(), "expires应为未来的unix时间戳")
  371. }
  372. // TC-0173: token无效
  373. func TestRefreshToken_InvalidToken(t *testing.T) {
  374. ctx := context.Background()
  375. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  376. srv := NewPermServer(svcCtx)
  377. _, err := srv.RefreshToken(ctx, &pb.RefreshTokenReq{
  378. RefreshToken: "invalid.token.string",
  379. })
  380. require.Error(t, err)
  381. assert.Equal(t, codes.Unauthenticated, status.Code(err))
  382. assert.Equal(t, "refreshToken无效或已过期", status.Convert(err).Message())
  383. }
  384. // TC-0174: 账号冻结
  385. func TestRefreshToken_AccountFrozen(t *testing.T) {
  386. ctx := context.Background()
  387. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  388. conn := testutil.GetTestSqlConn()
  389. now := time.Now().Unix()
  390. uid := testutil.UniqueId()
  391. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  392. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  393. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  394. Status: 2, CreateTime: now, UpdateTime: now,
  395. })
  396. require.NoError(t, err)
  397. uId, _ := uRes.LastInsertId()
  398. t.Cleanup(func() {
  399. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  400. })
  401. cfg := testutil.GetTestConfig()
  402. refreshToken, err := authHelper.GenerateRefreshToken(cfg.Auth.RefreshSecret, cfg.Auth.RefreshExpire, uId, "")
  403. require.NoError(t, err)
  404. srv := NewPermServer(svcCtx)
  405. _, err = srv.RefreshToken(ctx, &pb.RefreshTokenReq{
  406. RefreshToken: refreshToken,
  407. })
  408. require.Error(t, err)
  409. assert.Equal(t, codes.PermissionDenied, status.Code(err))
  410. assert.Equal(t, "账号已被冻结", status.Convert(err).Message())
  411. }
  412. // TC-0175: productCode回退到claims
  413. func TestRefreshToken_FallbackToClaimsProductCode(t *testing.T) {
  414. ctx := context.Background()
  415. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  416. conn := testutil.GetTestSqlConn()
  417. now := time.Now().Unix()
  418. uid := testutil.UniqueId()
  419. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  420. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  421. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  422. Status: 1, CreateTime: now, UpdateTime: now,
  423. })
  424. require.NoError(t, err)
  425. uId, _ := uRes.LastInsertId()
  426. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  427. Code: uid, Name: "test_prod", AppKey: uid + "_k", AppSecret: "s1",
  428. Status: 1, CreateTime: now, UpdateTime: now,
  429. })
  430. require.NoError(t, err)
  431. pId, _ := pRes.LastInsertId()
  432. mbrRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  433. ProductCode: uid, UserId: uId, MemberType: "MEMBER",
  434. Status: 1, CreateTime: now, UpdateTime: now,
  435. })
  436. require.NoError(t, err)
  437. mbrId, _ := mbrRes.LastInsertId()
  438. t.Cleanup(func() {
  439. testutil.CleanTable(ctx, conn, "`sys_product_member`", mbrId)
  440. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  441. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  442. })
  443. cfg := testutil.GetTestConfig()
  444. refreshToken, err := authHelper.GenerateRefreshToken(cfg.Auth.RefreshSecret, cfg.Auth.RefreshExpire, uId, uid)
  445. require.NoError(t, err)
  446. srv := NewPermServer(svcCtx)
  447. resp, err := srv.RefreshToken(ctx, &pb.RefreshTokenReq{
  448. RefreshToken: refreshToken,
  449. ProductCode: "",
  450. })
  451. require.NoError(t, err)
  452. assert.NotEmpty(t, resp.AccessToken)
  453. assert.Equal(t, refreshToken, resp.RefreshToken, "refreshToken应原样返回")
  454. }
  455. // TC-0176: 超管+productCode
  456. func TestRefreshToken_SuperAdminWithProductCode(t *testing.T) {
  457. ctx := context.Background()
  458. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  459. conn := testutil.GetTestSqlConn()
  460. now := time.Now().Unix()
  461. uid := testutil.UniqueId()
  462. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  463. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "sa",
  464. Avatar: sql.NullString{}, IsSuperAdmin: 1, MustChangePassword: 2,
  465. Status: 1, CreateTime: now, UpdateTime: now,
  466. })
  467. require.NoError(t, err)
  468. uId, _ := uRes.LastInsertId()
  469. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  470. Code: uid, Name: "test_prod", AppKey: uid + "_k", AppSecret: "s1",
  471. Status: 1, CreateTime: now, UpdateTime: now,
  472. })
  473. require.NoError(t, err)
  474. pId, _ := pRes.LastInsertId()
  475. pm1Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  476. ProductCode: uid, Name: "p1", Code: uid + "_c1",
  477. Status: 1, CreateTime: now, UpdateTime: now,
  478. })
  479. require.NoError(t, err)
  480. pm1Id, _ := pm1Res.LastInsertId()
  481. t.Cleanup(func() {
  482. testutil.CleanTable(ctx, conn, "`sys_perm`", pm1Id)
  483. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  484. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  485. })
  486. cfg := testutil.GetTestConfig()
  487. refreshToken, err := authHelper.GenerateRefreshToken(cfg.Auth.RefreshSecret, cfg.Auth.RefreshExpire, uId, uid)
  488. require.NoError(t, err)
  489. srv := NewPermServer(svcCtx)
  490. resp, err := srv.RefreshToken(ctx, &pb.RefreshTokenReq{
  491. RefreshToken: refreshToken,
  492. ProductCode: uid,
  493. })
  494. require.NoError(t, err)
  495. assert.NotEmpty(t, resp.AccessToken)
  496. assert.Equal(t, refreshToken, resp.RefreshToken, "refreshToken应原样返回")
  497. }
  498. // TC-0177: 普通用户+productCode
  499. func TestRefreshToken_NormalUserWithProductCode(t *testing.T) {
  500. ctx := context.Background()
  501. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  502. conn := testutil.GetTestSqlConn()
  503. now := time.Now().Unix()
  504. uid := testutil.UniqueId()
  505. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  506. Username: uid, Password: testutil.HashPassword("pass123"), Nickname: "nick",
  507. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  508. Status: 1, CreateTime: now, UpdateTime: now,
  509. })
  510. require.NoError(t, err)
  511. uId, _ := uRes.LastInsertId()
  512. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  513. Code: uid, Name: "test_prod", AppKey: uid + "_k", AppSecret: "s1",
  514. Status: 1, CreateTime: now, UpdateTime: now,
  515. })
  516. require.NoError(t, err)
  517. pId, _ := pRes.LastInsertId()
  518. mbrRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  519. ProductCode: uid, UserId: uId, MemberType: "MEMBER",
  520. Status: 1, CreateTime: now, UpdateTime: now,
  521. })
  522. require.NoError(t, err)
  523. mbrId, _ := mbrRes.LastInsertId()
  524. pm1Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  525. ProductCode: uid, Name: "p1", Code: uid + "_c1",
  526. Status: 1, CreateTime: now, UpdateTime: now,
  527. })
  528. require.NoError(t, err)
  529. pm1Id, _ := pm1Res.LastInsertId()
  530. roleRes, err := svcCtx.SysRoleModel.Insert(ctx, &roleModel.SysRole{
  531. ProductCode: uid, Name: uid + "_role", Status: 1, PermsLevel: 1,
  532. CreateTime: now, UpdateTime: now,
  533. })
  534. require.NoError(t, err)
  535. roleId, _ := roleRes.LastInsertId()
  536. urRes, err := svcCtx.SysUserRoleModel.Insert(ctx, &userRoleModel.SysUserRole{
  537. UserId: uId, RoleId: roleId, CreateTime: now, UpdateTime: now,
  538. })
  539. require.NoError(t, err)
  540. urId, _ := urRes.LastInsertId()
  541. rpRes, err := svcCtx.SysRolePermModel.Insert(ctx, &rolePermModel.SysRolePerm{
  542. RoleId: roleId, PermId: pm1Id, CreateTime: now, UpdateTime: now,
  543. })
  544. require.NoError(t, err)
  545. rpId, _ := rpRes.LastInsertId()
  546. t.Cleanup(func() {
  547. testutil.CleanTable(ctx, conn, "`sys_role_perm`", rpId)
  548. testutil.CleanTable(ctx, conn, "`sys_user_role`", urId)
  549. testutil.CleanTable(ctx, conn, "`sys_perm`", pm1Id)
  550. testutil.CleanTable(ctx, conn, "`sys_role`", roleId)
  551. testutil.CleanTable(ctx, conn, "`sys_product_member`", mbrId)
  552. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  553. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  554. })
  555. cfg := testutil.GetTestConfig()
  556. refreshToken, err := authHelper.GenerateRefreshToken(cfg.Auth.RefreshSecret, cfg.Auth.RefreshExpire, uId, uid)
  557. require.NoError(t, err)
  558. srv := NewPermServer(svcCtx)
  559. resp, err := srv.RefreshToken(ctx, &pb.RefreshTokenReq{
  560. RefreshToken: refreshToken,
  561. ProductCode: uid,
  562. })
  563. require.NoError(t, err)
  564. assert.NotEmpty(t, resp.AccessToken)
  565. assert.Equal(t, refreshToken, resp.RefreshToken, "refreshToken应原样返回")
  566. }
  567. // ---------- VerifyToken ----------
  568. // TC-0178: 有效token
  569. func TestVerifyToken_Valid(t *testing.T) {
  570. ctx := context.Background()
  571. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  572. cfg := testutil.GetTestConfig()
  573. accessToken, err := authHelper.GenerateAccessToken(
  574. cfg.Auth.AccessSecret, cfg.Auth.AccessExpire,
  575. 100, "testuser", "prod1", "ADMIN", []string{"perm_a", "perm_b"},
  576. )
  577. require.NoError(t, err)
  578. srv := NewPermServer(svcCtx)
  579. resp, err := srv.VerifyToken(ctx, &pb.VerifyTokenReq{AccessToken: accessToken})
  580. require.NoError(t, err)
  581. assert.True(t, resp.Valid)
  582. assert.Equal(t, int64(100), resp.UserId)
  583. assert.Equal(t, "testuser", resp.Username)
  584. assert.Equal(t, "ADMIN", resp.MemberType)
  585. assert.ElementsMatch(t, []string{"perm_a", "perm_b"}, resp.Perms)
  586. }
  587. // TC-0179: 无效token
  588. func TestVerifyToken_Invalid(t *testing.T) {
  589. ctx := context.Background()
  590. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  591. srv := NewPermServer(svcCtx)
  592. resp, err := srv.VerifyToken(ctx, &pb.VerifyTokenReq{AccessToken: "invalid.token.here"})
  593. require.NoError(t, err)
  594. assert.False(t, resp.Valid)
  595. }
  596. // TC-0180: 缺少userId
  597. func TestVerifyToken_MissingUserId(t *testing.T) {
  598. ctx := context.Background()
  599. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  600. cfg := testutil.GetTestConfig()
  601. // Generate a token without userId by using raw JWT
  602. token := createTokenWithoutUserId(cfg.Auth.AccessSecret)
  603. srv := NewPermServer(svcCtx)
  604. resp, err := srv.VerifyToken(ctx, &pb.VerifyTokenReq{AccessToken: token})
  605. require.NoError(t, err)
  606. assert.False(t, resp.Valid)
  607. }
  608. // ---------- GetUserPerms ----------
  609. // TC-0181: 用户不存在
  610. func TestGetUserPerms_UserNotFound(t *testing.T) {
  611. ctx := context.Background()
  612. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  613. srv := NewPermServer(svcCtx)
  614. _, err := srv.GetUserPerms(ctx, &pb.GetUserPermsReq{
  615. UserId: 999999999,
  616. ProductCode: "any_product",
  617. })
  618. require.Error(t, err)
  619. assert.Equal(t, codes.NotFound, status.Code(err))
  620. assert.Equal(t, "用户不存在", status.Convert(err).Message())
  621. }
  622. // TC-0182: 超管
  623. func TestGetUserPerms_SuperAdmin(t *testing.T) {
  624. ctx := context.Background()
  625. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  626. conn := testutil.GetTestSqlConn()
  627. now := time.Now().Unix()
  628. uid := testutil.UniqueId()
  629. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  630. Username: uid, Password: testutil.HashPassword("pass"), Nickname: "sa",
  631. Avatar: sql.NullString{}, IsSuperAdmin: 1, MustChangePassword: 2,
  632. Status: 1, CreateTime: now, UpdateTime: now,
  633. })
  634. require.NoError(t, err)
  635. uId, _ := uRes.LastInsertId()
  636. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  637. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: "s1",
  638. Status: 1, CreateTime: now, UpdateTime: now,
  639. })
  640. require.NoError(t, err)
  641. pId, _ := pRes.LastInsertId()
  642. pm1Res, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  643. ProductCode: uid, Name: "p1", Code: uid + "_c1",
  644. Status: 1, CreateTime: now, UpdateTime: now,
  645. })
  646. require.NoError(t, err)
  647. pm1Id, _ := pm1Res.LastInsertId()
  648. mRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  649. ProductCode: uid, UserId: uId, MemberType: "ADMIN",
  650. Status: 1, CreateTime: now, UpdateTime: now,
  651. })
  652. require.NoError(t, err)
  653. mId, _ := mRes.LastInsertId()
  654. t.Cleanup(func() {
  655. testutil.CleanTable(ctx, conn, "`sys_product_member`", mId)
  656. testutil.CleanTable(ctx, conn, "`sys_perm`", pm1Id)
  657. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  658. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  659. })
  660. srv := NewPermServer(svcCtx)
  661. resp, err := srv.GetUserPerms(ctx, &pb.GetUserPermsReq{
  662. UserId: uId,
  663. ProductCode: uid,
  664. })
  665. require.NoError(t, err)
  666. assert.Equal(t, "SUPER_ADMIN", resp.MemberType)
  667. assert.Contains(t, resp.Perms, uid+"_c1")
  668. }
  669. // TC-0165: 验证disabled计数
  670. func TestSyncPermissions_VerifyDisabledCount(t *testing.T) {
  671. ctx := context.Background()
  672. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  673. conn := testutil.GetTestSqlConn()
  674. now := time.Now().Unix()
  675. uid := testutil.UniqueId()
  676. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  677. Code: uid, Name: "test_prod", AppKey: uid, AppSecret: "secret1",
  678. Status: 1, CreateTime: now, UpdateTime: now,
  679. })
  680. require.NoError(t, err)
  681. pId, _ := pRes.LastInsertId()
  682. var permIds []int64
  683. for i := 0; i < 5; i++ {
  684. pmRes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  685. ProductCode: uid, Name: "p", Code: fmt.Sprintf("%s_c%d", uid, i),
  686. Status: 1, CreateTime: now, UpdateTime: now,
  687. })
  688. require.NoError(t, err)
  689. pmId, _ := pmRes.LastInsertId()
  690. permIds = append(permIds, pmId)
  691. }
  692. t.Cleanup(func() {
  693. testutil.CleanTable(ctx, conn, "`sys_perm`", permIds...)
  694. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  695. })
  696. srv := NewPermServer(svcCtx)
  697. resp, err := srv.SyncPermissions(ctx, &pb.SyncPermissionsReq{
  698. AppKey: uid,
  699. AppSecret: "secret1",
  700. Perms: []*pb.PermItem{
  701. {Code: fmt.Sprintf("%s_c0", uid), Name: "p"},
  702. {Code: fmt.Sprintf("%s_c1", uid), Name: "p"},
  703. },
  704. })
  705. require.NoError(t, err)
  706. assert.Equal(t, int64(3), resp.Disabled)
  707. }
  708. // TC-0183: MEMBER-DENY覆盖
  709. func TestGetUserPerms_MemberDENYOverride(t *testing.T) {
  710. ctx := context.Background()
  711. svcCtx := svc.NewServiceContext(testutil.GetTestConfig())
  712. conn := testutil.GetTestSqlConn()
  713. now := time.Now().Unix()
  714. uid := testutil.UniqueId()
  715. uRes, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  716. Username: uid, Password: testutil.HashPassword("pass"), Nickname: "nick",
  717. Avatar: sql.NullString{}, IsSuperAdmin: 2, MustChangePassword: 2,
  718. Status: 1, CreateTime: now, UpdateTime: now,
  719. })
  720. require.NoError(t, err)
  721. uId, _ := uRes.LastInsertId()
  722. pRes, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  723. Code: uid, Name: "test_prod", AppKey: uid + "_k", AppSecret: "s1",
  724. Status: 1, CreateTime: now, UpdateTime: now,
  725. })
  726. require.NoError(t, err)
  727. pId, _ := pRes.LastInsertId()
  728. mbrRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &memberModel.SysProductMember{
  729. ProductCode: uid, UserId: uId, MemberType: "MEMBER",
  730. Status: 1, CreateTime: now, UpdateTime: now,
  731. })
  732. require.NoError(t, err)
  733. mbrId, _ := mbrRes.LastInsertId()
  734. roleRes, err := svcCtx.SysRoleModel.Insert(ctx, &roleModel.SysRole{
  735. ProductCode: uid, Name: uid + "_role", Status: 1, PermsLevel: 1,
  736. CreateTime: now, UpdateTime: now,
  737. })
  738. require.NoError(t, err)
  739. roleId, _ := roleRes.LastInsertId()
  740. permARes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  741. ProductCode: uid, Name: "permA", Code: uid + "_pA",
  742. Status: 1, CreateTime: now, UpdateTime: now,
  743. })
  744. require.NoError(t, err)
  745. permAId, _ := permARes.LastInsertId()
  746. permBRes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  747. ProductCode: uid, Name: "permB", Code: uid + "_pB",
  748. Status: 1, CreateTime: now, UpdateTime: now,
  749. })
  750. require.NoError(t, err)
  751. permBId, _ := permBRes.LastInsertId()
  752. urRes, err := svcCtx.SysUserRoleModel.Insert(ctx, &userRoleModel.SysUserRole{
  753. UserId: uId, RoleId: roleId, CreateTime: now, UpdateTime: now,
  754. })
  755. require.NoError(t, err)
  756. urId, _ := urRes.LastInsertId()
  757. rpARes, err := svcCtx.SysRolePermModel.Insert(ctx, &rolePermModel.SysRolePerm{
  758. RoleId: roleId, PermId: permAId, CreateTime: now, UpdateTime: now,
  759. })
  760. require.NoError(t, err)
  761. rpAId, _ := rpARes.LastInsertId()
  762. rpBRes, err := svcCtx.SysRolePermModel.Insert(ctx, &rolePermModel.SysRolePerm{
  763. RoleId: roleId, PermId: permBId, CreateTime: now, UpdateTime: now,
  764. })
  765. require.NoError(t, err)
  766. rpBId, _ := rpBRes.LastInsertId()
  767. upRes, err := svcCtx.SysUserPermModel.Insert(ctx, &userPermModel.SysUserPerm{
  768. UserId: uId, PermId: permAId, Effect: "DENY",
  769. CreateTime: now, UpdateTime: now,
  770. })
  771. require.NoError(t, err)
  772. upId, _ := upRes.LastInsertId()
  773. t.Cleanup(func() {
  774. testutil.CleanTable(ctx, conn, "`sys_user_perm`", upId)
  775. testutil.CleanTable(ctx, conn, "`sys_role_perm`", rpAId, rpBId)
  776. testutil.CleanTable(ctx, conn, "`sys_user_role`", urId)
  777. testutil.CleanTable(ctx, conn, "`sys_perm`", permAId, permBId)
  778. testutil.CleanTable(ctx, conn, "`sys_role`", roleId)
  779. testutil.CleanTable(ctx, conn, "`sys_product_member`", mbrId)
  780. testutil.CleanTable(ctx, conn, "`sys_product`", pId)
  781. testutil.CleanTable(ctx, conn, "`sys_user`", uId)
  782. })
  783. srv := NewPermServer(svcCtx)
  784. resp, err := srv.GetUserPerms(ctx, &pb.GetUserPermsReq{
  785. UserId: uId,
  786. ProductCode: uid,
  787. })
  788. require.NoError(t, err)
  789. assert.Equal(t, "MEMBER", resp.MemberType)
  790. assert.Contains(t, resp.Perms, uid+"_pB")
  791. assert.NotContains(t, resp.Perms, uid+"_pA")
  792. }
  793. // helper: create a JWT with no userId claim
  794. func createTokenWithoutUserId(secret string) string {
  795. claims := jwt.MapClaims{
  796. "username": "test",
  797. "exp": time.Now().Add(time.Hour).Unix(),
  798. }
  799. token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
  800. s, _ := token.SignedString([]byte(secret))
  801. return s
  802. }