leonardo: get-session 按 cookie 串行,避免并发刷新令牌被判重用
This commit is contained in:
@@ -66,10 +66,14 @@ type Client struct {
|
|||||||
// persists it; keeping it here means an unpersisted rotation still works for
|
// persists it; keeping it here means an unpersisted rotation still works for
|
||||||
// the rest of the process's life.
|
// the rest of the process's life.
|
||||||
rotated map[string]string
|
rotated map[string]string
|
||||||
|
// refreshing serialises get-session per cookie. Two concurrent refreshes hand
|
||||||
|
// Cognito the same refresh token twice and its reuse detection revokes the
|
||||||
|
// whole session — the account then answers 401 forever.
|
||||||
|
refreshing map[string]*sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(proxy string) *Client {
|
func NewClient(proxy string) *Client {
|
||||||
return &Client{proxy: strings.TrimSpace(proxy), sessions: map[string]*Session{}, rotated: map[string]string{}}
|
return &Client{proxy: strings.TrimSpace(proxy), sessions: map[string]*Session{}, rotated: map[string]string{}, refreshing: map[string]*sync.Mutex{}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) SetProxy(proxy string) {
|
func (c *Client) SetProxy(proxy string) {
|
||||||
@@ -193,6 +197,18 @@ func (c *Client) GetSession(ctx context.Context, cookie string) (*Session, error
|
|||||||
}
|
}
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
|
|
||||||
|
// Only one refresh per cookie at a time; the others wait and then re-use the
|
||||||
|
// token it minted.
|
||||||
|
gate := c.refreshGate(cookie)
|
||||||
|
gate.Lock()
|
||||||
|
defer gate.Unlock()
|
||||||
|
c.mu.Lock()
|
||||||
|
if cs, ok := c.sessions[cookie]; ok && cs.ExpiresAt-60 > time.Now().Unix() {
|
||||||
|
c.mu.Unlock()
|
||||||
|
return cs, nil
|
||||||
|
}
|
||||||
|
c.mu.Unlock()
|
||||||
|
|
||||||
// Use the freshest known value (an earlier response may have rotated the
|
// Use the freshest known value (an earlier response may have rotated the
|
||||||
// better-auth cookie cache) rather than the possibly stale stored cookie.
|
// better-auth cookie cache) rather than the possibly stale stored cookie.
|
||||||
send := cookie
|
send := cookie
|
||||||
@@ -327,6 +343,18 @@ func (c *Client) GetSession(ctx context.Context, cookie string) (*Session, error
|
|||||||
return sess, nil
|
return sess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// refreshGate returns the per-cookie lock that serialises get-session refreshes.
|
||||||
|
func (c *Client) refreshGate(cookie string) *sync.Mutex {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
gate, ok := c.refreshing[cookie]
|
||||||
|
if !ok {
|
||||||
|
gate = &sync.Mutex{}
|
||||||
|
c.refreshing[cookie] = gate
|
||||||
|
}
|
||||||
|
return gate
|
||||||
|
}
|
||||||
|
|
||||||
// warmSession calls cross-origin-cookie, whose response refreshes better-auth's
|
// warmSession calls cross-origin-cookie, whose response refreshes better-auth's
|
||||||
// cookie cache and CF_Access_Token. It returns the Set-Cookie headers; a
|
// cookie cache and CF_Access_Token. It returns the Set-Cookie headers; a
|
||||||
// checkpoint answer (403/429) is an error, since get-session would then be cold.
|
// checkpoint answer (403/429) is an error, since get-session would then be cold.
|
||||||
|
|||||||
Reference in New Issue
Block a user