loginByCapLogic.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. // Code scaffolded by goctl. Safe to edit.
  2. // goctl 1.10.1
  3. package pub
  4. import (
  5. "bytes"
  6. "context"
  7. "encoding/json"
  8. "io"
  9. "net/http"
  10. "strings"
  11. "time"
  12. "perms-system-server/internal/config"
  13. "perms-system-server/internal/middleware"
  14. "perms-system-server/internal/response"
  15. "perms-system-server/internal/svc"
  16. "perms-system-server/internal/types"
  17. "github.com/zeromicro/go-zero/core/logx"
  18. )
  19. type LoginByCapLogic struct {
  20. logx.Logger
  21. ctx context.Context
  22. svcCtx *svc.ServiceContext
  23. }
  24. func NewLoginByCapLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginByCapLogic {
  25. return &LoginByCapLogic{
  26. Logger: logx.WithContext(ctx),
  27. ctx: ctx,
  28. svcCtx: svcCtx,
  29. }
  30. }
  31. func (l *LoginByCapLogic) LoginByCap(req *types.LoginByCapReq) (*types.LoginResp, error) {
  32. if err := verifyCapToken(l.ctx, l.svcCtx.Config.Capjs, req.CapToken, l.Logger); err != nil {
  33. return nil, err
  34. }
  35. clientIP := middleware.GetClientIP(l.ctx)
  36. result, err := ValidateProductLogin(l.ctx, l.svcCtx, req.Username, req.Password, req.ProductCode, clientIP)
  37. if err != nil {
  38. if le, ok := err.(*LoginError); ok {
  39. switch le.Code {
  40. case 400:
  41. return nil, response.ErrBadRequest(le.Message)
  42. case 401:
  43. return nil, response.ErrUnauthorized(le.Message)
  44. case 403:
  45. return nil, response.ErrForbidden(le.Message)
  46. case 429:
  47. return nil, response.NewCodeError(429, le.Message)
  48. }
  49. }
  50. return nil, err
  51. }
  52. ud := result.UserDetails
  53. return &types.LoginResp{
  54. AccessToken: result.AccessToken,
  55. RefreshToken: result.RefreshToken,
  56. Expires: time.Now().Unix() + l.svcCtx.Config.Auth.AccessExpire,
  57. UserInfo: types.UserInfo{
  58. UserId: ud.UserId,
  59. Username: ud.Username,
  60. Nickname: ud.Nickname,
  61. Avatar: ud.Avatar,
  62. Email: ud.Email,
  63. Phone: ud.Phone,
  64. IsSuperAdmin: ud.IsSuperAdminRaw,
  65. MustChangePassword: ud.MustChangePwdRaw,
  66. MemberType: ud.MemberType,
  67. Perms: ud.Perms,
  68. },
  69. }, nil
  70. }
  71. // verifyCapToken 向 cap.js 服务端发送 siteverify 请求,校验人机验证令牌。
  72. // 供产品端和管理端的 cap.js 登录逻辑共用。
  73. func verifyCapToken(ctx context.Context, cfg config.CapjsConf, capToken string, logger logx.Logger) error {
  74. if cfg.Enable != 1 || cfg.EndpointURL == "" {
  75. return response.ErrBadRequest("当前未启用人机验证,请使用图片验证码登录")
  76. }
  77. if strings.TrimSpace(capToken) == "" {
  78. return response.ErrBadRequest("人机验证不能为空")
  79. }
  80. body, _ := json.Marshal(map[string]string{
  81. "secret": cfg.Secret,
  82. "response": capToken,
  83. })
  84. verifyURL := cfg.EndpointURL + "/" + cfg.Key + "/siteverify"
  85. req, err := http.NewRequestWithContext(ctx, http.MethodPost, verifyURL, bytes.NewBuffer(body))
  86. if err != nil {
  87. logger.Errorf("verifyCapToken: create request failed: %v", err)
  88. return response.NewCodeError(500, "人机验证校验失败")
  89. }
  90. req.Header.Set("Content-Type", "application/json")
  91. client := &http.Client{Timeout: 10 * time.Second}
  92. res, err := client.Do(req)
  93. if err != nil {
  94. logger.Errorf("verifyCapToken: send request failed: %v", err)
  95. return response.NewCodeError(500, "人机验证校验失败")
  96. }
  97. defer res.Body.Close()
  98. raw, err := io.ReadAll(res.Body)
  99. if err != nil {
  100. logger.Errorf("verifyCapToken: read response failed: %v", err)
  101. return response.NewCodeError(500, "人机验证校验失败")
  102. }
  103. var result struct {
  104. Success bool `json:"success"`
  105. }
  106. if err := json.Unmarshal(raw, &result); err != nil {
  107. logger.Errorf("verifyCapToken: unmarshal failed: %v, body: %s", err, raw)
  108. return response.NewCodeError(500, "人机验证校验失败")
  109. }
  110. if !result.Success {
  111. return response.ErrBadRequest("人机验证失败,请重试")
  112. }
  113. return nil
  114. }