loginByCapLogic_test.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. package pub
  2. import (
  3. "context"
  4. "encoding/json"
  5. "errors"
  6. "net/http"
  7. "net/http/httptest"
  8. "testing"
  9. "time"
  10. "perms-system-server/internal/config"
  11. productmemberModel "perms-system-server/internal/model/productmember"
  12. "perms-system-server/internal/response"
  13. "perms-system-server/internal/svc"
  14. "perms-system-server/internal/testutil"
  15. "perms-system-server/internal/types"
  16. "github.com/stretchr/testify/assert"
  17. "github.com/stretchr/testify/require"
  18. )
  19. func newCapMockServer(success bool) *httptest.Server {
  20. return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  21. w.Header().Set("Content-Type", "application/json")
  22. json.NewEncoder(w).Encode(map[string]bool{"success": success})
  23. }))
  24. }
  25. func newCapEnabledSvcCtx(endpointURL string) *svc.ServiceContext {
  26. cfg := testutil.GetTestConfig()
  27. cfg.Capjs = config.CapjsConf{
  28. Enable: 1,
  29. EndpointURL: endpointURL,
  30. Key: "test-key",
  31. Secret: "test-secret",
  32. }
  33. return svc.NewServiceContext(cfg)
  34. }
  35. // TC-1219: cap.js 未启用时调用 LoginByCap
  36. func TestLoginByCap_CapDisabled(t *testing.T) {
  37. cfg := testutil.GetTestConfig()
  38. cfg.Capjs = config.CapjsConf{Enable: 0}
  39. svcCtx := svc.NewServiceContext(cfg)
  40. logic := NewLoginByCapLogic(context.Background(), svcCtx)
  41. resp, err := logic.LoginByCap(&types.LoginByCapReq{
  42. Username: "user",
  43. Password: "pass",
  44. ProductCode: "pc",
  45. CapToken: "some-token",
  46. })
  47. require.Nil(t, resp)
  48. require.Error(t, err)
  49. var codeErr *response.CodeError
  50. require.True(t, errors.As(err, &codeErr))
  51. assert.Equal(t, 400, codeErr.Code())
  52. assert.Contains(t, codeErr.Error(), "当前未启用人机验证")
  53. }
  54. // TC-1220: capToken 为空
  55. func TestLoginByCap_EmptyCapToken(t *testing.T) {
  56. server := newCapMockServer(true)
  57. defer server.Close()
  58. svcCtx := newCapEnabledSvcCtx(server.URL)
  59. logic := NewLoginByCapLogic(context.Background(), svcCtx)
  60. resp, err := logic.LoginByCap(&types.LoginByCapReq{
  61. Username: "user",
  62. Password: "pass",
  63. ProductCode: "pc",
  64. CapToken: "",
  65. })
  66. require.Nil(t, resp)
  67. require.Error(t, err)
  68. var codeErr *response.CodeError
  69. require.True(t, errors.As(err, &codeErr))
  70. assert.Equal(t, 400, codeErr.Code())
  71. assert.Contains(t, codeErr.Error(), "人机验证不能为空")
  72. }
  73. // TC-1221: capToken 无效(远端校验失败)
  74. func TestLoginByCap_InvalidCapToken(t *testing.T) {
  75. server := newCapMockServer(false)
  76. defer server.Close()
  77. svcCtx := newCapEnabledSvcCtx(server.URL)
  78. logic := NewLoginByCapLogic(context.Background(), svcCtx)
  79. resp, err := logic.LoginByCap(&types.LoginByCapReq{
  80. Username: "user",
  81. Password: "pass",
  82. ProductCode: "pc",
  83. CapToken: "invalid-token",
  84. })
  85. require.Nil(t, resp)
  86. require.Error(t, err)
  87. var codeErr *response.CodeError
  88. require.True(t, errors.As(err, &codeErr))
  89. assert.Equal(t, 400, codeErr.Code())
  90. assert.Contains(t, codeErr.Error(), "人机验证失败")
  91. }
  92. // TC-1222: capToken 有效 + 正常登录
  93. func TestLoginByCap_ValidToken_Success(t *testing.T) {
  94. ctx := context.Background()
  95. server := newCapMockServer(true)
  96. defer server.Close()
  97. svcCtx := newCapEnabledSvcCtx(server.URL)
  98. conn := testutil.GetTestSqlConn()
  99. username := testutil.UniqueId()
  100. password := "TestPass123"
  101. pc := testutil.UniqueId()
  102. now := time.Now().Unix()
  103. userId, cleanUser := insertTestUser(t, ctx, svcCtx, username, password, 1, 2)
  104. t.Cleanup(cleanUser)
  105. _, cleanProduct := insertTestProduct(t, ctx, svcCtx, pc, testutil.UniqueId(), "secret")
  106. t.Cleanup(cleanProduct)
  107. pmRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &productmemberModel.SysProductMember{
  108. ProductCode: pc, UserId: userId, MemberType: "MEMBER", Status: 1, CreateTime: now, UpdateTime: now,
  109. })
  110. require.NoError(t, err)
  111. pmId, _ := pmRes.LastInsertId()
  112. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_product_member`", pmId) })
  113. logic := NewLoginByCapLogic(ctx, svcCtx)
  114. resp, err := logic.LoginByCap(&types.LoginByCapReq{
  115. Username: username,
  116. Password: password,
  117. ProductCode: pc,
  118. CapToken: "valid-token",
  119. })
  120. require.NoError(t, err)
  121. require.NotNil(t, resp)
  122. assert.NotEmpty(t, resp.AccessToken)
  123. assert.NotEmpty(t, resp.RefreshToken)
  124. assert.Equal(t, username, resp.UserInfo.Username)
  125. }
  126. // TC-1223: capToken 有效 + 密码错误
  127. func TestLoginByCap_ValidToken_WrongPassword(t *testing.T) {
  128. ctx := context.Background()
  129. server := newCapMockServer(true)
  130. defer server.Close()
  131. svcCtx := newCapEnabledSvcCtx(server.URL)
  132. username := testutil.UniqueId()
  133. pc := testutil.UniqueId()
  134. _, cleanUser := insertTestUser(t, ctx, svcCtx, username, "RealPass123", 1, 2)
  135. t.Cleanup(cleanUser)
  136. _, cleanProduct := insertTestProduct(t, ctx, svcCtx, pc, testutil.UniqueId(), "secret")
  137. t.Cleanup(cleanProduct)
  138. logic := NewLoginByCapLogic(ctx, svcCtx)
  139. resp, err := logic.LoginByCap(&types.LoginByCapReq{
  140. Username: username,
  141. Password: "WrongPass",
  142. ProductCode: pc,
  143. CapToken: "valid-token",
  144. })
  145. require.Nil(t, resp)
  146. require.Error(t, err)
  147. var codeErr *response.CodeError
  148. require.True(t, errors.As(err, &codeErr))
  149. assert.Equal(t, 401, codeErr.Code())
  150. }
  151. // TC-1224: capToken 有效 + 超管被拒绝
  152. func TestLoginByCap_ValidToken_SuperAdminRejected(t *testing.T) {
  153. ctx := context.Background()
  154. server := newCapMockServer(true)
  155. defer server.Close()
  156. svcCtx := newCapEnabledSvcCtx(server.URL)
  157. username := testutil.UniqueId()
  158. password := "TestPass123"
  159. pc := testutil.UniqueId()
  160. _, cleanUser := insertSuperAdmin(t, ctx, svcCtx, username, password)
  161. t.Cleanup(cleanUser)
  162. _, cleanProduct := insertTestProduct(t, ctx, svcCtx, pc, testutil.UniqueId(), "secret")
  163. t.Cleanup(cleanProduct)
  164. logic := NewLoginByCapLogic(ctx, svcCtx)
  165. resp, err := logic.LoginByCap(&types.LoginByCapReq{
  166. Username: username,
  167. Password: password,
  168. ProductCode: pc,
  169. CapToken: "valid-token",
  170. })
  171. require.Nil(t, resp)
  172. require.Error(t, err)
  173. var codeErr *response.CodeError
  174. require.True(t, errors.As(err, &codeErr))
  175. assert.Equal(t, 403, codeErr.Code())
  176. }