Files
likedream/internal/application/cpdaily/login/common.go
T
2026-03-11 21:11:50 +08:00

197 lines
5.8 KiB
Go

package login
import (
"context"
"fmt"
"likedream-goframe/internal/application/cookiejar"
"likedream-goframe/internal/application/cpdaily/school"
"likedream-goframe/internal/application/httpclient"
"likedream-goframe/internal/common/errors"
"likedream-goframe/internal/ent/cpuser"
"likedream-goframe/internal/framework/logger"
"likedream-goframe/internal/utils"
"strings"
"github.com/samber/oops"
"go.uber.org/zap"
"resty.dev/v3"
)
func ActivateSession(ctx context.Context, host string, client *resty.Client) {
// 处理cookie,干掉path
jar := client.CookieJar()
realJar := jar.(*cookiejar.PersistCookieJar)
realJar.RemoveCookieInfo()
client.SetCookieJar(realJar)
client.SetRedirectPolicy(resty.FlexibleRedirectPolicy(20))
host = strings.TrimSuffix(host, "/")
activateStep1 := func() {
sessionResponse, err := client.R().
WithContext(ctx).
Get(fmt.Sprintf("%s/wec-im-group/group/groupMember/checkImInitFlag", host))
utils.OkOrPanic(err)
defer sessionResponse.Body.Close()
if !sessionResponse.IsSuccess() && sessionResponse.StatusCode() != 502 {
utils.OkOrPanic(errors.NewBusinessError(503, "Session激活失败"),
func(err error) error {
return oops.
WithContext(ctx).
With("host", host).
Wrap(err)
})
}
}
activateStep2 := func() {
sessionResponse, err := client.R().
WithContext(ctx).
SetBody(map[string]any{}).
Post(fmt.Sprintf("%s/wec-counselor-attendance-apps/student/attendance/getStuSignInfosByWeekMonth", host))
utils.OkOrPanic(err)
defer sessionResponse.Body.Close()
if !sessionResponse.IsSuccess() {
if sessionResponse.StatusCode() == 405 {
return
}
utils.OkOrPanic(errors.NewBusinessError(503, "Session激活失败"),
func(err error) error {
return oops.
WithContext(ctx).
With("host", host).
Wrap(err)
})
}
responseContentType := sessionResponse.Header().Get("Content-Type")
if !strings.Contains(responseContentType, "json") {
utils.OkOrPanic(errors.NewBusinessError(503, "Session激活失败"),
func(err error) error {
return oops.
WithContext(ctx).
With("host", host).
With("response_content_type", responseContentType).
Wrap(err)
})
}
}
activateStep1()
activateStep2()
client.SetRedirectPolicy(resty.NoRedirectPolicy())
}
func CookieEnabled(ctx context.Context, host string, client *resty.Client, loginType cpuser.LoginType) bool {
client.SetRedirectPolicy(resty.NoRedirectPolicy())
host = strings.TrimSuffix(host, "/")
sessionResponse, err := client.R().
WithContext(ctx).
SetBody(map[string]any{}).
Post(fmt.Sprintf("%s/wec-counselor-attendance-apps/student/attendance/getStuAttendacesInOneDay", host))
utils.OkOrPanic(err)
needLogin := sessionResponse.StatusCode() == 302
return !needLogin
}
// RefreshCookieParams 刷新 cookie 所需的用户参数
type RefreshCookieParams struct {
ID int64
Cookie string
Tgc string
LoginType cpuser.LoginType
Username string
Password string
SchoolID string
}
// RefreshCookieResult 刷新 cookie 的结果
type RefreshCookieResult struct {
Client *resty.Client
Cookie string
Tgc string
}
// EnsureCookieValid 检测 cookie 是否过期,过期则自动刷新。
// phone 类型用 TGC 刷新,account 类型用账号密码重新登录。
func EnsureCookieValid(ctx context.Context, params *RefreshCookieParams, schoolDetail *school.SchoolDetailInfo) *RefreshCookieResult {
client := GetClient(ctx, params.Cookie)
if CookieEnabled(ctx, schoolDetail.WecloudUrl, client, params.LoginType) {
logger.Logger.Info("[TGC] cookie有效,无需刷新",
zap.Int64("userId", params.ID),
zap.String("loginType", string(params.LoginType)),
)
return &RefreshCookieResult{Client: client, Cookie: params.Cookie, Tgc: params.Tgc}
}
logger.Logger.Info("[TGC] cookie已失效,开始刷新",
zap.Int64("userId", params.ID),
zap.String("loginType", string(params.LoginType)),
zap.Bool("tgcEmpty", params.Tgc == ""),
)
var newCookie, newTgc string
if params.LoginType == cpuser.LoginTypePhone {
if params.Tgc == "" {
utils.OkOrPanic(errors.NewBusinessError(500, "TGC为空,请重新通过短信验证码登录"))
}
smsHandler := NewSmsWithoutDeviceID()
newCookie, newTgc = smsHandler.RefreshByTgc(ctx, params.Tgc, params.SchoolID)
logger.Logger.Info("[TGC] RefreshByTgc完成",
zap.Int64("userId", params.ID),
zap.Bool("cookieChanged", newCookie != params.Cookie),
)
} else {
loginExecutor := GetCpdailyLoginBySchoolInfo(ctx, schoolDetail)
loginExecutor.Login(ctx, schoolDetail, params.Username, params.Password)
newCookie = loginExecutor.GetCookieString()
newTgc = params.Tgc
}
return &RefreshCookieResult{
Client: GetClient(ctx, newCookie),
Cookie: newCookie,
Tgc: newTgc,
}
}
func GetClient(ctx context.Context, cookie string) *resty.Client {
cookieJar := cookiejar.NewPersistCookieJar()
cookieJar.Deserialize(cookie)
// 不使用 Clone,创建全新的独立 client 实例避免状态共享
client := httpclient.NewCpdailyClient()
client.SetCookieJar(cookieJar)
return client
}
func SendDynamicCodeByPhone(ctx context.Context, username string, host string, client *resty.Client) {
host = strings.TrimSuffix(host, "/")
response, err := client.R().
WithContext(ctx).
SetFormData(map[string]string{
"userName": username,
"authCodeTypeName": "reAuthDynamicCodeType",
}).
Post(fmt.Sprintf("%s/authserver/dynamicCode/getDynamicCodeByReauth.do", host))
utils.OkOrPanic(err, func(err error) error {
return oops.
In("多因子短信发送").
With("username", username).
Wrap(err)
})
responseJson := utils.ReadGjsonResult(response.Body)
if responseJson.Get("res").String() != "success" {
utils.OkOrPanic(errors.NewBusinessError(500, "多因子短信发送失败,原因是"+responseJson.Get("returnMessage").String()))
}
}