| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- // Code scaffolded by goctl. Safe to edit.
- // goctl 1.10.1
- package pub
- import (
- "bytes"
- "context"
- "encoding/json"
- "io"
- "net/http"
- "strings"
- "time"
- "perms-system-server/internal/config"
- "perms-system-server/internal/middleware"
- "perms-system-server/internal/response"
- "perms-system-server/internal/svc"
- "perms-system-server/internal/types"
- "github.com/zeromicro/go-zero/core/logx"
- )
- type LoginByCapLogic struct {
- logx.Logger
- ctx context.Context
- svcCtx *svc.ServiceContext
- }
- func NewLoginByCapLogic(ctx context.Context, svcCtx *svc.ServiceContext) *LoginByCapLogic {
- return &LoginByCapLogic{
- Logger: logx.WithContext(ctx),
- ctx: ctx,
- svcCtx: svcCtx,
- }
- }
- func (l *LoginByCapLogic) LoginByCap(req *types.LoginByCapReq) (*types.LoginResp, error) {
- if err := verifyCapToken(l.ctx, l.svcCtx.Config.Capjs, req.CapToken, l.Logger); err != nil {
- return nil, err
- }
- clientIP := middleware.GetClientIP(l.ctx)
- result, err := ValidateProductLogin(l.ctx, l.svcCtx, req.Username, req.Password, req.ProductCode, clientIP)
- if err != nil {
- if le, ok := err.(*LoginError); ok {
- switch le.Code {
- case 400:
- return nil, response.ErrBadRequest(le.Message)
- case 401:
- return nil, response.ErrUnauthorized(le.Message)
- case 403:
- return nil, response.ErrForbidden(le.Message)
- case 429:
- return nil, response.NewCodeError(429, le.Message)
- }
- }
- return nil, err
- }
- ud := result.UserDetails
- return &types.LoginResp{
- AccessToken: result.AccessToken,
- RefreshToken: result.RefreshToken,
- Expires: time.Now().Unix() + l.svcCtx.Config.Auth.AccessExpire,
- UserInfo: types.UserInfo{
- UserId: ud.UserId,
- Username: ud.Username,
- Nickname: ud.Nickname,
- Avatar: ud.Avatar,
- Email: ud.Email,
- Phone: ud.Phone,
- IsSuperAdmin: ud.IsSuperAdminRaw,
- MustChangePassword: ud.MustChangePwdRaw,
- MemberType: ud.MemberType,
- Perms: ud.Perms,
- },
- }, nil
- }
- // verifyCapToken 向 cap.js 服务端发送 siteverify 请求,校验人机验证令牌。
- // 供产品端和管理端的 cap.js 登录逻辑共用。
- func verifyCapToken(ctx context.Context, cfg config.CapjsConf, capToken string, logger logx.Logger) error {
- if cfg.Enable != 1 || cfg.EndpointURL == "" {
- return response.ErrBadRequest("当前未启用人机验证,请使用图片验证码登录")
- }
- if strings.TrimSpace(capToken) == "" {
- return response.ErrBadRequest("人机验证不能为空")
- }
- body, _ := json.Marshal(map[string]string{
- "secret": cfg.Secret,
- "response": capToken,
- })
- verifyURL := cfg.EndpointURL + "/" + cfg.Key + "/siteverify"
- req, err := http.NewRequestWithContext(ctx, http.MethodPost, verifyURL, bytes.NewBuffer(body))
- if err != nil {
- logger.Errorf("verifyCapToken: create request failed: %v", err)
- return response.NewCodeError(500, "人机验证校验失败")
- }
- req.Header.Set("Content-Type", "application/json")
- client := &http.Client{Timeout: 10 * time.Second}
- res, err := client.Do(req)
- if err != nil {
- logger.Errorf("verifyCapToken: send request failed: %v", err)
- return response.NewCodeError(500, "人机验证校验失败")
- }
- defer res.Body.Close()
- raw, err := io.ReadAll(res.Body)
- if err != nil {
- logger.Errorf("verifyCapToken: read response failed: %v", err)
- return response.NewCodeError(500, "人机验证校验失败")
- }
- var result struct {
- Success bool `json:"success"`
- }
- if err := json.Unmarshal(raw, &result); err != nil {
- logger.Errorf("verifyCapToken: unmarshal failed: %v, body: %s", err, raw)
- return response.NewCodeError(500, "人机验证校验失败")
- }
- if !result.Success {
- return response.ErrBadRequest("人机验证失败,请重试")
- }
- return nil
- }
|