@@ -15,6 +15,7 @@ import (
"likedream-goframe/internal/utils"
"net/http"
"net/url"
"strings"
"github.com/bytedance/sonic"
"github.com/samber/oops"
@@ -284,25 +285,88 @@ func (s *SmsLoginHandler) GetCookieString() string {
// RefreshByTgc 使用保存的完整 cookie(包含 CASTGC 等长期凭证)重新去学校换取 CAS cookie。
// tgc 参数是 SetLoginCookie 之后序列化的完整 cookie jar,包含 CASTGC(有效期10年)、
// sessionToken 等认证信息,可以直接用来重新激活 session。
// sessionToken 等认证信息。流程:先用 sessionToken 调用 getImUserToken 换取新的 CAS cookie,
// 再激活 session。
func ( s * SmsLoginHandler ) RefreshByTgc ( ctx context . Context , tgc string , schoolId string ) ( cookie string , newTgc string ) {
jar := cookiejar . NewPersistCookieJar ( )
jar . Deserialize ( tgc )
// 合并所有 host 的 cookie 到 global,消除因多 host 存储导致的重复 cookie
jar . RemoveCookieInfo ( )
s . client = httpclient . NewCpdailyClient ( )
s . client . SetCookieJar ( jar )
detail := school . GetSchoolDetail ( ctx , schoolId )
logger . Logger . Info ( "[TGC] RefreshByTgc 开始用CASTGC重新激活session " ,
logger . Logger . Info ( "[TGC] RefreshByTgc 开始用TGC换取CAS cookie " ,
zap . String ( "schoolId" , schoolId ) ,
zap . String ( "wecloudUrl" , detail . WecloudUrl ) ,
zap . Int ( "tgcLen" , len ( tgc ) ) ,
)
// 用保存的 cookie(含 CASTGC)重新激活 session
ActivateSession ( ctx , detail . WecloudUrl , s . client )
// 从 cookie jar 中提取 sessionToken,用于换取新的 CAS cookie
schoolUrl , _ := url . Parse ( detail . WecloudUrl )
sessionToken := ""
for _ , c := range jar . Cookies ( schoolUrl ) {
if c . Name == "sessionToken" {
sessionToken = c . Value
break
}
}
logger . Logger . Info ( "[TGC] RefreshByTgc ActivateSession完成" )
if sessionToken != "" {
// 换取新的 CAS cookie(与 SetLoginCookie 相同的流程)
getCookieUrl := fmt . Sprintf ( "%s%s" , detail . WecloudUrl , "/wec-im-group/group/imUserToken/getImUserToken" )
ampCookieMap := map [ string ] any {
"AMP2" : [ ] map [ string ] any {
{ "path" : "/" , "value" : sessionToken , "domain" : "" , "name" : "sessionToken" } ,
} ,
"AMP1" : [ ] map [ string ] any {
{ "path" : "/" , "value" : sessionToken , "domain" : "" , "name" : "sessionToken" } ,
} ,
}
ampTokenString , e := sonic . Marshal ( ampCookieMap )
utils . OkOrPanic ( e , oops . WithContext ( ctx ) . Wrap )
ampTokenEncrypted := cryptoutil . DesEncrypt ( ampTokenString , cryptoutil . Normal )
ampToken := base64 . StdEncoding . EncodeToString ( ampTokenEncrypted )
ctx = utils . NewCpdailySmsContextBuilder ( ) .
WithDeviceID ( s . deviceID ) .
WithTenantID ( detail . Id ) .
WithSessionToken ( sessionToken ) .
Build ( ctx )
// 使用不复制 Cookie 头的重定向策略,避免旧 Cookie 覆盖 jar 中更新的值
s . client . SetRedirectPolicy ( resty . RedirectPolicyFunc ( func ( req * http . Request , via [ ] * http . Request ) error {
if len ( via ) >= 50 {
return fmt . Errorf ( "resty: stopped after 50 redirects" )
}
// 只复制非 Cookie 头,让 jar 自动管理 Cookie
for key , val := range via [ 0 ] . Header {
if ! strings . EqualFold ( key , "Cookie" ) {
req . Header [ key ] = val
}
}
return nil
} ) )
req := s . client . R ( ) .
SetHeader ( "AmpCookies" , ampToken ) .
SetContext ( ctx )
setSmsRequestHeaders ( ctx , req )
resp , e := req . Get ( getCookieUrl )
utils . OkOrPanic ( e , oops . WithContext ( ctx ) . Wrap )
respJson := utils . ReadJson [ cpdailySmsCommonResponse [ any ] ] ( resp . Body )
respJson . EnsureSuccess ( )
logger . Logger . Info ( "[TGC] RefreshByTgc 换取CAS cookie完成" )
} else {
logger . Logger . Warn ( "[TGC] RefreshByTgc 未找到sessionToken,跳过换取CAS cookie步骤" )
}
newTgc = tgc // TGC 保持不变(CASTGC 有效期10年)
cookie = s . GetCookieString ( )