loginLogic_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. package pub
  2. import (
  3. "context"
  4. "database/sql"
  5. "errors"
  6. "testing"
  7. "time"
  8. permModel "perms-system-server/internal/model/perm"
  9. productModel "perms-system-server/internal/model/product"
  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/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 newTestSvcCtx() *svc.ServiceContext {
  20. return svc.NewServiceContext(testutil.GetTestConfig())
  21. }
  22. func insertTestUser(t *testing.T, ctx context.Context, svcCtx *svc.ServiceContext, username, password string, status, isSuperAdmin int64) (int64, func()) {
  23. t.Helper()
  24. conn := testutil.GetTestSqlConn()
  25. now := time.Now().Unix()
  26. hashed := testutil.HashPassword(password)
  27. res, err := svcCtx.SysUserModel.Insert(ctx, &userModel.SysUser{
  28. Username: username,
  29. Password: hashed,
  30. Nickname: username,
  31. Avatar: sql.NullString{},
  32. Email: username + "@test.com",
  33. Phone: "13800000000",
  34. Remark: "",
  35. DeptId: 0,
  36. IsSuperAdmin: isSuperAdmin,
  37. MustChangePassword: 2,
  38. Status: status,
  39. CreateTime: now,
  40. UpdateTime: now,
  41. })
  42. require.NoError(t, err)
  43. id, _ := res.LastInsertId()
  44. cleanup := func() {
  45. testutil.CleanTable(ctx, conn, "`sys_user`", id)
  46. }
  47. return id, cleanup
  48. }
  49. func insertTestProduct(t *testing.T, ctx context.Context, svcCtx *svc.ServiceContext, code, appKey, appSecret string) (int64, func()) {
  50. t.Helper()
  51. conn := testutil.GetTestSqlConn()
  52. now := time.Now().Unix()
  53. res, err := svcCtx.SysProductModel.Insert(ctx, &productModel.SysProduct{
  54. Code: code,
  55. Name: code,
  56. AppKey: appKey,
  57. AppSecret: appSecret,
  58. Status: 1,
  59. CreateTime: now,
  60. UpdateTime: now,
  61. })
  62. require.NoError(t, err)
  63. id, _ := res.LastInsertId()
  64. cleanup := func() {
  65. testutil.CleanTable(ctx, conn, "`sys_product`", id)
  66. }
  67. return id, cleanup
  68. }
  69. // TC-0001: 正常登录-不带productCode
  70. func TestLogin_NormalWithoutProductCode(t *testing.T) {
  71. ctx := context.Background()
  72. svcCtx := newTestSvcCtx()
  73. username := testutil.UniqueId()
  74. password := "TestPass123"
  75. _, cleanUser := insertTestUser(t, ctx, svcCtx, username, password, 1, 2)
  76. t.Cleanup(cleanUser)
  77. logic := NewLoginLogic(ctx, svcCtx)
  78. resp, err := logic.Login(&types.LoginReq{
  79. Username: username,
  80. Password: password,
  81. })
  82. require.NoError(t, err)
  83. require.NotNil(t, resp)
  84. assert.NotEmpty(t, resp.AccessToken)
  85. assert.NotEmpty(t, resp.RefreshToken)
  86. assert.True(t, resp.Expires > time.Now().Unix(), "expires应为未来的unix时间戳")
  87. assert.Equal(t, username, resp.UserInfo.Username)
  88. assert.Empty(t, resp.UserInfo.MemberType)
  89. assert.Nil(t, resp.UserInfo.Perms)
  90. }
  91. // TC-0002: 正常登录-带productCode
  92. func TestLogin_NormalWithProductCode(t *testing.T) {
  93. ctx := context.Background()
  94. svcCtx := newTestSvcCtx()
  95. conn := testutil.GetTestSqlConn()
  96. username := testutil.UniqueId()
  97. password := "TestPass123"
  98. pc := testutil.UniqueId()
  99. now := time.Now().Unix()
  100. userId, cleanUser := insertTestUser(t, ctx, svcCtx, username, password, 1, 2)
  101. t.Cleanup(cleanUser)
  102. _, cleanProduct := insertTestProduct(t, ctx, svcCtx, pc, testutil.UniqueId(), "secret")
  103. t.Cleanup(cleanProduct)
  104. pmRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &productmemberModel.SysProductMember{
  105. ProductCode: pc, UserId: userId, MemberType: "ADMIN", Status: 1, CreateTime: now, UpdateTime: now,
  106. })
  107. require.NoError(t, err)
  108. pmId, _ := pmRes.LastInsertId()
  109. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_product_member`", pmId) })
  110. permRes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  111. ProductCode: pc, Name: "perm1", Code: testutil.UniqueId(), Status: 1, CreateTime: now, UpdateTime: now,
  112. })
  113. require.NoError(t, err)
  114. permId, _ := permRes.LastInsertId()
  115. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_perm`", permId) })
  116. logic := NewLoginLogic(ctx, svcCtx)
  117. resp, err := logic.Login(&types.LoginReq{
  118. Username: username,
  119. Password: password,
  120. ProductCode: pc,
  121. })
  122. require.NoError(t, err)
  123. require.NotNil(t, resp)
  124. assert.Equal(t, "ADMIN", resp.UserInfo.MemberType)
  125. assert.NotEmpty(t, resp.UserInfo.Perms)
  126. }
  127. // TC-0003: 超管登录+productCode
  128. func TestLogin_SuperAdminWithProductCode(t *testing.T) {
  129. ctx := context.Background()
  130. svcCtx := newTestSvcCtx()
  131. conn := testutil.GetTestSqlConn()
  132. username := testutil.UniqueId()
  133. password := "TestPass123"
  134. pc := testutil.UniqueId()
  135. now := time.Now().Unix()
  136. _, cleanUser := insertTestUser(t, ctx, svcCtx, username, password, 1, 1)
  137. t.Cleanup(cleanUser)
  138. _, cleanProduct := insertTestProduct(t, ctx, svcCtx, pc, testutil.UniqueId(), "secret")
  139. t.Cleanup(cleanProduct)
  140. permCode := testutil.UniqueId()
  141. permRes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  142. ProductCode: pc, Name: "sa_perm", Code: permCode, Status: 1, CreateTime: now, UpdateTime: now,
  143. })
  144. require.NoError(t, err)
  145. permId, _ := permRes.LastInsertId()
  146. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_perm`", permId) })
  147. logic := NewLoginLogic(ctx, svcCtx)
  148. resp, err := logic.Login(&types.LoginReq{
  149. Username: username,
  150. Password: password,
  151. ProductCode: pc,
  152. })
  153. require.NoError(t, err)
  154. require.NotNil(t, resp)
  155. assert.Equal(t, "SUPER_ADMIN", resp.UserInfo.MemberType)
  156. assert.Contains(t, resp.UserInfo.Perms, permCode)
  157. assert.Equal(t, int64(1), resp.UserInfo.IsSuperAdmin)
  158. }
  159. // TC-0004: 超管登录-无productCode
  160. func TestLogin_SuperAdminWithoutProductCode(t *testing.T) {
  161. ctx := context.Background()
  162. svcCtx := newTestSvcCtx()
  163. username := testutil.UniqueId()
  164. password := "TestPass123"
  165. _, cleanUser := insertTestUser(t, ctx, svcCtx, username, password, 1, 1)
  166. t.Cleanup(cleanUser)
  167. logic := NewLoginLogic(ctx, svcCtx)
  168. resp, err := logic.Login(&types.LoginReq{
  169. Username: username,
  170. Password: password,
  171. })
  172. require.NoError(t, err)
  173. require.NotNil(t, resp)
  174. assert.Equal(t, "SUPER_ADMIN", resp.UserInfo.MemberType)
  175. assert.Nil(t, resp.UserInfo.Perms)
  176. }
  177. // TC-0005: 用户不存在
  178. func TestLogin_UserNotFound(t *testing.T) {
  179. ctx := context.Background()
  180. svcCtx := newTestSvcCtx()
  181. logic := NewLoginLogic(ctx, svcCtx)
  182. resp, err := logic.Login(&types.LoginReq{
  183. Username: "nonexistent_" + testutil.UniqueId(),
  184. Password: "whatever",
  185. })
  186. require.Nil(t, resp)
  187. require.Error(t, err)
  188. var codeErr *response.CodeError
  189. require.True(t, errors.As(err, &codeErr))
  190. assert.Equal(t, 401, codeErr.Code())
  191. assert.Equal(t, "用户名或密码错误", codeErr.Error())
  192. }
  193. // TC-0007: 密码错误
  194. func TestLogin_WrongPassword(t *testing.T) {
  195. ctx := context.Background()
  196. svcCtx := newTestSvcCtx()
  197. username := testutil.UniqueId()
  198. _, cleanUser := insertTestUser(t, ctx, svcCtx, username, "CorrectPass", 1, 2)
  199. t.Cleanup(cleanUser)
  200. logic := NewLoginLogic(ctx, svcCtx)
  201. resp, err := logic.Login(&types.LoginReq{
  202. Username: username,
  203. Password: "WrongPass",
  204. })
  205. require.Nil(t, resp)
  206. require.Error(t, err)
  207. var codeErr *response.CodeError
  208. require.True(t, errors.As(err, &codeErr))
  209. assert.Equal(t, 401, codeErr.Code())
  210. assert.Equal(t, "用户名或密码错误", codeErr.Error())
  211. }
  212. // TC-0008: 账号冻结
  213. func TestLogin_AccountFrozen(t *testing.T) {
  214. ctx := context.Background()
  215. svcCtx := newTestSvcCtx()
  216. username := testutil.UniqueId()
  217. password := "TestPass123"
  218. _, cleanUser := insertTestUser(t, ctx, svcCtx, username, password, 2, 2)
  219. t.Cleanup(cleanUser)
  220. logic := NewLoginLogic(ctx, svcCtx)
  221. resp, err := logic.Login(&types.LoginReq{
  222. Username: username,
  223. Password: password,
  224. })
  225. require.Nil(t, resp)
  226. require.Error(t, err)
  227. var codeErr *response.CodeError
  228. require.True(t, errors.As(err, &codeErr))
  229. assert.Equal(t, 403, codeErr.Code())
  230. assert.Equal(t, "账号已被冻结", codeErr.Error())
  231. }
  232. // TC-0009: 非产品成员
  233. func TestLogin_NonMemberWithProductCode(t *testing.T) {
  234. ctx := context.Background()
  235. svcCtx := newTestSvcCtx()
  236. username := testutil.UniqueId()
  237. password := "TestPass123"
  238. pc := testutil.UniqueId()
  239. _, cleanUser := insertTestUser(t, ctx, svcCtx, username, password, 1, 2)
  240. t.Cleanup(cleanUser)
  241. _, cleanProduct := insertTestProduct(t, ctx, svcCtx, pc, testutil.UniqueId(), "secret")
  242. t.Cleanup(cleanProduct)
  243. logic := NewLoginLogic(ctx, svcCtx)
  244. resp, err := logic.Login(&types.LoginReq{
  245. Username: username,
  246. Password: password,
  247. ProductCode: pc,
  248. })
  249. require.NoError(t, err)
  250. require.NotNil(t, resp)
  251. assert.Empty(t, resp.UserInfo.MemberType)
  252. assert.Nil(t, resp.UserInfo.Perms)
  253. }
  254. // TC-0010: DEVELOPER成员
  255. func TestLogin_DeveloperMember(t *testing.T) {
  256. ctx := context.Background()
  257. svcCtx := newTestSvcCtx()
  258. conn := testutil.GetTestSqlConn()
  259. username := testutil.UniqueId()
  260. password := "TestPass123"
  261. pc := testutil.UniqueId()
  262. now := time.Now().Unix()
  263. userId, cleanUser := insertTestUser(t, ctx, svcCtx, username, password, 1, 2)
  264. t.Cleanup(cleanUser)
  265. _, cleanProduct := insertTestProduct(t, ctx, svcCtx, pc, testutil.UniqueId(), "secret")
  266. t.Cleanup(cleanProduct)
  267. pmRes, err := svcCtx.SysProductMemberModel.Insert(ctx, &productmemberModel.SysProductMember{
  268. ProductCode: pc, UserId: userId, MemberType: "DEVELOPER", Status: 1, CreateTime: now, UpdateTime: now,
  269. })
  270. require.NoError(t, err)
  271. pmId, _ := pmRes.LastInsertId()
  272. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_product_member`", pmId) })
  273. permCode := testutil.UniqueId()
  274. permRes, err := svcCtx.SysPermModel.Insert(ctx, &permModel.SysPerm{
  275. ProductCode: pc, Name: "dev_perm", Code: permCode, Status: 1, CreateTime: now, UpdateTime: now,
  276. })
  277. require.NoError(t, err)
  278. permId, _ := permRes.LastInsertId()
  279. t.Cleanup(func() { testutil.CleanTable(ctx, conn, "`sys_perm`", permId) })
  280. logic := NewLoginLogic(ctx, svcCtx)
  281. resp, err := logic.Login(&types.LoginReq{
  282. Username: username,
  283. Password: password,
  284. ProductCode: pc,
  285. })
  286. require.NoError(t, err)
  287. require.NotNil(t, resp)
  288. assert.Equal(t, "DEVELOPER", resp.UserInfo.MemberType)
  289. assert.Contains(t, resp.UserInfo.Perms, permCode)
  290. }
  291. // TC-0011: SQL注入
  292. func TestLogin_SQLInjection(t *testing.T) {
  293. ctx := context.Background()
  294. svcCtx := newTestSvcCtx()
  295. logic := NewLoginLogic(ctx, svcCtx)
  296. resp, err := logic.Login(&types.LoginReq{
  297. Username: "' OR 1=1 --",
  298. Password: "anything",
  299. })
  300. require.Nil(t, resp)
  301. require.Error(t, err)
  302. var codeErr *response.CodeError
  303. require.True(t, errors.As(err, &codeErr))
  304. assert.Equal(t, 401, codeErr.Code())
  305. assert.Equal(t, "用户名或密码错误", codeErr.Error())
  306. }