refreshTokenLogic_test.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. package pub
  2. import (
  3. "context"
  4. "database/sql"
  5. "errors"
  6. "testing"
  7. "time"
  8. authHelper "perms-system-server/internal/logic/auth"
  9. permModel "perms-system-server/internal/model/perm"
  10. productmemberModel "perms-system-server/internal/model/productmember"
  11. userModel "perms-system-server/internal/model/user"
  12. "perms-system-server/internal/response"
  13. "perms-system-server/internal/testutil"
  14. "perms-system-server/internal/types"
  15. "github.com/stretchr/testify/assert"
  16. "github.com/stretchr/testify/require"
  17. )
  18. func insertRefreshTestUser(t *testing.T, ctx context.Context, username, password string, status, isSuperAdmin int64) (int64, func()) {
  19. t.Helper()
  20. svcCtx := newTestSvcCtx()
  21. conn := testutil.GetTestSqlConn()
  22. now := time.Now().Unix()
  23. hashed := testutil.HashPassword(password)
  24. res, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  25. Username: username,
  26. Password: hashed,
  27. Nickname: username,
  28. Avatar: sql.NullString{},
  29. Email: username + "@test.com",
  30. Phone: "13800000000",
  31. Remark: "",
  32. DeptId: 0,
  33. IsSuperAdmin: isSuperAdmin,
  34. MustChangePassword: 2,
  35. Status: status,
  36. CreateTime: now,
  37. UpdateTime: now,
  38. })
  39. require.NoError(t, err)
  40. id, _ := res.LastInsertId()
  41. cleanup := func() {
  42. testutil.CleanTable(ctx, conn, "`sys_user`", id)
  43. }
  44. return id, cleanup
  45. }
  46. // TC-0013: 正常刷新(refreshToken从header获取,原样返回不重新生成)
  47. func TestRefreshToken_Normal(t *testing.T) {
  48. ctx := context.Background()
  49. svcCtx := newTestSvcCtx()
  50. username := testutil.UniqueId()
  51. password := "TestPass123"
  52. userId, cleanUser := insertRefreshTestUser(t, ctx, username, password, 1, 2)
  53. t.Cleanup(cleanUser)
  54. refreshToken, err := authHelper.GenerateRefreshToken(
  55. svcCtx.Config.Auth.RefreshSecret,
  56. svcCtx.Config.Auth.RefreshExpire,
  57. userId, "",
  58. )
  59. require.NoError(t, err)
  60. logic := NewRefreshTokenLogic(ctx, svcCtx)
  61. resp, err := logic.RefreshToken(&types.RefreshTokenReq{
  62. Authorization: "Bearer " + refreshToken,
  63. })
  64. require.NoError(t, err)
  65. require.NotNil(t, resp)
  66. assert.NotEmpty(t, resp.AccessToken)
  67. assert.Equal(t, refreshToken, resp.RefreshToken, "refreshToken应原样返回,不重新生成")
  68. assert.NotEqual(t, resp.AccessToken, resp.RefreshToken, "accessToken和refreshToken应不同")
  69. assert.True(t, resp.Expires > time.Now().Unix(), "expires应为未来的unix时间戳")
  70. assert.Equal(t, userId, resp.UserInfo.UserId)
  71. assert.Equal(t, username, resp.UserInfo.Username)
  72. }
  73. // TC-0014: 不带productCode(回退)
  74. func TestRefreshToken_FallbackToClaimsProductCode(t *testing.T) {
  75. ctx := context.Background()
  76. svcCtx := newTestSvcCtx()
  77. conn := testutil.GetTestSqlConn()
  78. username := testutil.UniqueId()
  79. password := "TestPass123"
  80. pc := testutil.UniqueId()
  81. now := time.Now().Unix()
  82. userId, cleanUser := insertRefreshTestUser(t, ctx, username, password, 1, 2)
  83. t.Cleanup(cleanUser)
  84. _, cleanProduct := insertTestProduct(t, ctx, svcCtx, pc, testutil.UniqueId(), "secret")
  85. t.Cleanup(cleanProduct)
  86. pmRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &productmemberModel.SysProductMember{
  87. ProductCode: pc, UserId: userId, MemberType: "ADMIN", Status: 1, CreateTime: now, UpdateTime: now,
  88. })
  89. require.NoError(t, err)
  90. pmId, _ := pmRes.LastInsertId()
  91. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_product_member`", pmId) })
  92. permCode := testutil.UniqueId()
  93. permRes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  94. ProductCode: pc, Name: "refresh_perm", Code: permCode, Status: 1, CreateTime: now, UpdateTime: now,
  95. })
  96. require.NoError(t, err)
  97. permId, _ := permRes.LastInsertId()
  98. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_perm`", permId) })
  99. refreshToken, err := authHelper.GenerateRefreshToken(
  100. svcCtx.Config.Auth.RefreshSecret,
  101. svcCtx.Config.Auth.RefreshExpire,
  102. userId, pc,
  103. )
  104. require.NoError(t, err)
  105. logic := NewRefreshTokenLogic(ctx, svcCtx)
  106. resp, err := logic.RefreshToken(&types.RefreshTokenReq{
  107. Authorization: "Bearer " + refreshToken,
  108. })
  109. require.NoError(t, err)
  110. require.NotNil(t, resp)
  111. assert.Equal(t, "ADMIN", resp.UserInfo.MemberType)
  112. assert.Contains(t, resp.UserInfo.Perms, permCode)
  113. }
  114. // TC-0015: token无效
  115. func TestRefreshToken_InvalidToken(t *testing.T) {
  116. ctx := context.Background()
  117. svcCtx := newTestSvcCtx()
  118. logic := NewRefreshTokenLogic(ctx, svcCtx)
  119. resp, err := logic.RefreshToken(&types.RefreshTokenReq{
  120. Authorization: "Bearer invalid.token.string",
  121. })
  122. require.Nil(t, resp)
  123. require.Error(t, err)
  124. var codeErr *response.CodeError
  125. require.True(t, errors.As(err, &codeErr))
  126. assert.Equal(t, 401, codeErr.Code())
  127. assert.Equal(t, "refreshToken无效或已过期", codeErr.Error())
  128. }
  129. // TC-0016: 用户已删除(UserDetailsLoader 返回 Status=0 → 403 账号已被冻结)
  130. func TestRefreshToken_UserDeleted(t *testing.T) {
  131. ctx := context.Background()
  132. svcCtx := newTestSvcCtx()
  133. nonExistentUserId := int64(999999999)
  134. refreshToken, err := authHelper.GenerateRefreshToken(
  135. svcCtx.Config.Auth.RefreshSecret,
  136. svcCtx.Config.Auth.RefreshExpire,
  137. nonExistentUserId, "",
  138. )
  139. require.NoError(t, err)
  140. logic := NewRefreshTokenLogic(ctx, svcCtx)
  141. resp, err := logic.RefreshToken(&types.RefreshTokenReq{
  142. Authorization: "Bearer " + refreshToken,
  143. })
  144. require.Nil(t, resp)
  145. require.Error(t, err)
  146. var codeErr *response.CodeError
  147. require.True(t, errors.As(err, &codeErr))
  148. assert.Equal(t, 403, codeErr.Code())
  149. assert.Equal(t, "账号已被冻结", codeErr.Error())
  150. }
  151. // TC-0017: 账号冻结
  152. func TestRefreshToken_AccountFrozen(t *testing.T) {
  153. ctx := context.Background()
  154. svcCtx := newTestSvcCtx()
  155. username := testutil.UniqueId()
  156. password := "TestPass123"
  157. userId, cleanUser := insertRefreshTestUser(t, ctx, username, password, 2, 2)
  158. t.Cleanup(cleanUser)
  159. refreshToken, err := authHelper.GenerateRefreshToken(
  160. svcCtx.Config.Auth.RefreshSecret,
  161. svcCtx.Config.Auth.RefreshExpire,
  162. userId, "",
  163. )
  164. require.NoError(t, err)
  165. logic := NewRefreshTokenLogic(ctx, svcCtx)
  166. resp, err := logic.RefreshToken(&types.RefreshTokenReq{
  167. Authorization: "Bearer " + refreshToken,
  168. })
  169. require.Nil(t, resp)
  170. require.Error(t, err)
  171. var codeErr *response.CodeError
  172. require.True(t, errors.As(err, &codeErr))
  173. assert.Equal(t, 403, codeErr.Code())
  174. assert.Equal(t, "账号已被冻结", codeErr.Error())
  175. }
  176. // TC-0018: 超管+productCode(refreshToken原样返回)
  177. func TestRefreshToken_SuperAdminWithProductCode(t *testing.T) {
  178. ctx := context.Background()
  179. svcCtx := newTestSvcCtx()
  180. conn := testutil.GetTestSqlConn()
  181. username := testutil.UniqueId()
  182. password := "TestPass123"
  183. pc := testutil.UniqueId()
  184. now := time.Now().Unix()
  185. userId, cleanUser := insertRefreshTestUser(t, ctx, username, password, 1, 1)
  186. t.Cleanup(cleanUser)
  187. _, cleanProduct := insertTestProduct(t, ctx, svcCtx, pc, testutil.UniqueId(), "secret")
  188. t.Cleanup(cleanProduct)
  189. permCode := testutil.UniqueId()
  190. permRes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  191. ProductCode: pc, Name: "sa_refresh_perm", Code: permCode, Status: 1, CreateTime: now, UpdateTime: now,
  192. })
  193. require.NoError(t, err)
  194. permId, _ := permRes.LastInsertId()
  195. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_perm`", permId) })
  196. refreshToken, err := authHelper.GenerateRefreshToken(
  197. svcCtx.Config.Auth.RefreshSecret,
  198. svcCtx.Config.Auth.RefreshExpire,
  199. userId, "",
  200. )
  201. require.NoError(t, err)
  202. logic := NewRefreshTokenLogic(ctx, svcCtx)
  203. resp, err := logic.RefreshToken(&types.RefreshTokenReq{
  204. Authorization: "Bearer " + refreshToken,
  205. ProductCode: pc,
  206. })
  207. require.NoError(t, err)
  208. require.NotNil(t, resp)
  209. assert.Equal(t, refreshToken, resp.RefreshToken, "refreshToken应原样返回,不重新生成")
  210. assert.Equal(t, "SUPER_ADMIN", resp.UserInfo.MemberType)
  211. assert.Contains(t, resp.UserInfo.Perms, permCode)
  212. assert.Equal(t, int64(1), resp.UserInfo.IsSuperAdmin)
  213. }