Files
2026-07-27 19:31:43 +08:00

96 lines
3.1 KiB
Go

package auth
import (
"context"
"time"
"litepan/internal/domain"
"litepan/internal/driver"
)
// Refresh 执行一次认证刷新(主动/被动共用入口,含 per-account 锁)。
func (s *Service) Refresh(ctx context.Context, accountID int64, caller driver.RefreshCaller) (driver.RefreshOutcome, error) {
unlock := s.locks.Lock(accountID)
defer unlock()
return s.refreshUnlocked(ctx, accountID, caller)
}
func (s *Service) refreshUnlocked(ctx context.Context, accountID int64, caller driver.RefreshCaller) (driver.RefreshOutcome, error) {
if s.drivers == nil {
err := domain.Errorf(domain.CodeInternal, "认证服务缺少驱动管理器")
return driver.RefreshRetryable, err
}
drv, err := s.drivers.Get(ctx, accountID)
if err != nil {
s.log.Warn("auth refresh get driver", "account", accountID, "err", err)
return driver.RefreshRetryable, err
}
refresher, ok := drv.(driver.AuthRefresher)
if !ok {
err := domain.Errorf(domain.CodeNotImplement, "驱动不支持认证刷新")
return driver.RefreshRetryable, err
}
st, err := s.loadState(ctx, accountID)
if err != nil {
s.log.Warn("auth refresh load state", "account", accountID, "err", err)
return driver.RefreshRetryable, err
}
outcome, rerr := refresher.RefreshAuth(ctx, caller)
if outcome == driver.RefreshSuccess {
st, _ = s.loadState(ctx, accountID)
s.applyTokenSchedule(drv, st)
now := s.nowTime()
name := s.accountName(ctx, accountID)
if st.Status != domain.AuthActive || st.LastRefreshAt.IsZero() || now.Sub(st.LastRefreshAt) > 3*time.Second {
s.markSuccess(ctx, accountID, st)
} else if err := s.authStates.Upsert(ctx, st); err != nil {
s.log.Warn("auth update schedule", "account", accountID, "err", err)
}
if caller == driver.CallerPassive {
s.log.Info("账号被动认证刷新成功", "account_id", accountID, "account", name)
}
return outcome, nil
}
if rerr == nil {
rerr = domain.Errf(domain.CodeAuthExpired)
}
s.handleFailure(ctx, accountID, st, outcome, caller, rerr)
s.log.Warn("auth refresh failed", "account", accountID, "caller", caller, "outcome", outcome, "err", rerr)
return outcome, rerr
}
// onCredentialsPersisted 驱动内联刷新写回 token 时同步认证成功态(如 123 apiCall 自动续期)。
func (s *Service) onCredentialsPersisted(ctx context.Context, accountID int64) {
st, err := s.loadState(ctx, accountID)
if err != nil {
return
}
if s.accounts != nil {
if acc, aerr := s.accounts.Get(ctx, accountID); aerr == nil && acc != nil {
if drv, ok := driver.New(acc.DriverType); ok {
s.applyTokenSchedule(drv, st)
}
}
}
name := s.accountName(ctx, accountID)
s.log.Info("请求链路触发认证凭证回写", "account_id", accountID, "account", name)
s.markSuccess(ctx, accountID, st)
}
func (s *Service) applyTokenSchedule(drv driver.Driver, st *domain.AuthState) {
cfg := drv.Config()
now := s.nowTime()
switch cfg.AuthType {
case driver.AuthToken:
if cfg.TokenLifetime > 0 {
st.TokenExpires = now.Add(cfg.TokenLifetime)
}
case driver.AuthCookie:
if cfg.HealthCheckInterval > 0 {
st.CookieExpires = now.Add(cfg.HealthCheckInterval)
}
}
}