package authser import ( "encoding/json" "fmt" "net/http" "net/url" "strings" "time" "videoweb/app/service/upstream" "videoweb/pub/common/useragent" "github.com/gin-gonic/gin" ) const ( guestPath = "/api/app/auth/guest" cookieMaxAge = 7 * 24 * 3600 ) // GuestLogin 调用上游游客登录,站点不提供注册/登录,上游内容接口依赖游客会话。 func GuestLogin(c *gin.Context, req GuestLoginReq) (*APIEnvelope, *LoginResp, error) { var env APIEnvelope if _, err := upstream.PostJSON(c, guestPath, req, &env); err != nil { return nil, nil, err } if env.Code != 200 { return &env, nil, nil } user, err := decodeLoginData(env.Data) if err != nil { return &env, nil, err } return &env, user, nil } func decodeLoginData(raw json.RawMessage) (*LoginResp, error) { if len(raw) == 0 || string(raw) == "null" || string(raw) == `""` { return nil, fmt.Errorf("empty login data") } var user LoginResp if err := json.Unmarshal(raw, &user); err != nil { return nil, err } return &user, nil } // SetAuthCookies 写入游客会话 cookie。 func SetAuthCookies(c *gin.Context, user *LoginResp) { if c == nil || user == nil { return } secure := c.Request != nil && c.Request.TLS != nil if strings.TrimSpace(user.Token) != "" { setCookie(c, "token", user.Token, secure) } if sid := useragent.SIDFromRequest(c.Request); sid != "" { setCookie(c, "sid", sid, secure) } } func setCookie(c *gin.Context, name, value string, secure bool) { // Cookie Value 仅允许 ASCII;使用 PathEscape(空格→%20),与前端 encodeURIComponent 一致。 http.SetCookie(c.Writer, &http.Cookie{ Name: name, Value: url.PathEscape(value), Path: "/", MaxAge: cookieMaxAge, HttpOnly: false, Secure: secure, SameSite: http.SameSiteLaxMode, Expires: time.Now().Add(7 * 24 * time.Hour), }) } func cookieValue(c *gin.Context, name string) string { ck, err := c.Request.Cookie(name) if err != nil || ck == nil { return "" } raw := strings.TrimSpace(ck.Value) if raw == "" { return "" } // QueryUnescape 同时兼容历史 QueryEscape(+)与 PathEscape(%20) if decoded, err := url.QueryUnescape(raw); err == nil { return strings.TrimSpace(decoded) } return raw } // ClearAuthCookies 清除会话 cookie,同时清理旧版账号体系遗留的用户信息 cookie。 func ClearAuthCookies(c *gin.Context) { for _, name := range authCookieNames() { http.SetCookie(c.Writer, &http.Cookie{ Name: name, Value: "", Path: "/", MaxAge: -1, HttpOnly: false, SameSite: http.SameSiteLaxMode, }) } } func authCookieNames() []string { return []string{ "token", "_token_", "sid", "_s_token_", "userId", "accountNo", "nickName", "introduction", "avatar", "email", "inviteCode", "recharge", "vipType", "currentVipExpire", "showCardId", "showCardName", "userType", "isRegister", "guest_skip_auto", } }