diff --git a/AIStudyApp/AIStudyApp/Core/Auth/AuthManager.swift b/AIStudyApp/AIStudyApp/Core/Auth/AuthManager.swift index b2d5200..51e8cbc 100644 --- a/AIStudyApp/AIStudyApp/Core/Auth/AuthManager.swift +++ b/AIStudyApp/AIStudyApp/Core/Auth/AuthManager.swift @@ -30,9 +30,10 @@ final class AuthManager: ObservableObject { init() { tokenExpiredObserver = NotificationCenter.default.addObserver( forName: .tokenExpired, object: nil, queue: .main - ) { [weak self] _ in + ) { [weak self] notification in + let errorCode = notification.userInfo?["errorCode"] as? String Task { @MainActor [weak self] in - self?.handleUnauthorized() + self?.handleUnauthorized(errorCode: errorCode) } } } @@ -59,6 +60,14 @@ final class AuthManager: ObservableObject { let _: UserProfileResponse = try await APIClient.shared.request("/users/me") session = .authenticated } catch { + // 如果 /users/me 返回了特定错误码(禁用/删除),直接切状态,不尝试 refresh + if let apiError = error as? APIError, let code = apiError.errorCode { + await APIClient.shared.setToken(nil) + KeychainHelper.clear() + applyErrorCode(code) + return + } + session = .refreshing if let refreshed = await tryRefresh() { await APIClient.shared.setToken(refreshed.accessToken) @@ -120,11 +129,15 @@ final class AuthManager: ObservableObject { // MARK: - Private - private func handleUnauthorized() { + private func handleUnauthorized(errorCode: String? = nil) { Task { await APIClient.shared.setToken(nil) KeychainHelper.clear() - session = .unauthenticated + if let code = errorCode { + applyErrorCode(code) + } else { + session = .unauthenticated + } } } diff --git a/AIStudyApp/AIStudyApp/Core/Network/APIClient.swift b/AIStudyApp/AIStudyApp/Core/Network/APIClient.swift index 8a42954..dc9d673 100644 --- a/AIStudyApp/AIStudyApp/Core/Network/APIClient.swift +++ b/AIStudyApp/AIStudyApp/Core/Network/APIClient.swift @@ -69,10 +69,12 @@ actor APIClient { self.token = newToken return try await performRequest(path, method: method, body: body, queryItems: queryItems, isRetry: true) } - await notifyTokenExpired() + let info = extractErrorInfo(data) + await notifyTokenExpired(errorCode: info.errorCode) throw decodeServerError(data, fallback: APIError.unauthorized) case 401: - throw decodeServerError(data, fallback: APIError.unauthorized) + let info = extractErrorInfo(data) + throw APIError.serverError(info.message ?? "未授权", code: info.errorCode) case 400..<500: let msg = String(data: data, encoding: .utf8) ?? "" throw APIError.serverError(msg) @@ -99,9 +101,13 @@ actor APIClient { } } - private func notifyTokenExpired() async { + private func notifyTokenExpired(errorCode: String? = nil) async { + var userInfo: [AnyHashable: Any]? = nil + if let code = errorCode { + userInfo = ["errorCode": code] + } await MainActor.run { - NotificationCenter.default.post(name: .tokenExpired, object: nil) + NotificationCenter.default.post(name: .tokenExpired, object: nil, userInfo: userInfo) } }