permserver_test.go 39 KB

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