From 1adba4d2278a29f8b774c4d2ef31a9da4e776cd9 Mon Sep 17 00:00:00 2001 From: Shuming Liu Date: Tue, 1 Sep 2026 08:41:52 +0800 Subject: [PATCH] fix: send auth token with sentence boundary API requests --- .../UserInterfaceState.xcuserstate | Bin 22397 -> 22578 bytes ios/OralTrainer/Config.swift | 3 +++ ios/OralTrainer/Services/HTTPClient.swift | 7 +++++-- .../Services/SentenceBoundaryAPI.swift | 7 ++++++- ios/OralTrainer/Views/AuthView.swift | 3 +++ 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/ios/OralTrainer.xcodeproj/project.xcworkspace/xcuserdata/liushuming.xcuserdatad/UserInterfaceState.xcuserstate b/ios/OralTrainer.xcodeproj/project.xcworkspace/xcuserdata/liushuming.xcuserdatad/UserInterfaceState.xcuserstate index af3cff7eddcb017a063d55195108f18d81af5475..0cbb5fcee33d180fa97b2b99f05b4d72f60d67ac 100644 GIT binary patch delta 10145 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 S!)%JGd$Kd@p7r-E>;C{Cne=1; diff --git a/ios/OralTrainer/Config.swift b/ios/OralTrainer/Config.swift index 48e4c07..ee12455 100644 --- a/ios/OralTrainer/Config.swift +++ b/ios/OralTrainer/Config.swift @@ -17,4 +17,7 @@ enum AppConfig { static let assessmentTimeout: TimeInterval = 180 static let sha256Pattern = #"^[0-9a-fA-F]{64}$"# + + /// 当前登录用户的认证 token,由 AuthManager 在登录/注销时设置。 + static var authToken: String = "" } diff --git a/ios/OralTrainer/Services/HTTPClient.swift b/ios/OralTrainer/Services/HTTPClient.swift index 9801fbb..38fff5d 100644 --- a/ios/OralTrainer/Services/HTTPClient.swift +++ b/ios/OralTrainer/Services/HTTPClient.swift @@ -25,14 +25,17 @@ enum HTTPClient { _ type: T.Type, baseURL: String, path: String, - timeout: TimeInterval + timeout: TimeInterval, + additionalHeaders: [String: String] = [:] ) async throws -> (value: T, effectiveBaseURL: String) { + var headers = ["Accept": "application/json"] + headers.merge(additionalHeaders) { _, new in new } let result = try await execute( baseURL: baseURL, path: path, method: "GET", timeout: timeout, - headers: ["Accept": "application/json"] + headers: headers ) guard (200...299).contains(result.statusCode) else { let body = String(data: result.body, encoding: .utf8) ?? "" diff --git a/ios/OralTrainer/Services/SentenceBoundaryAPI.swift b/ios/OralTrainer/Services/SentenceBoundaryAPI.swift index e3bba32..656f923 100644 --- a/ios/OralTrainer/Services/SentenceBoundaryAPI.swift +++ b/ios/OralTrainer/Services/SentenceBoundaryAPI.swift @@ -20,11 +20,16 @@ enum SentenceBoundaryAPI { guard hash.range(of: AppConfig.sha256Pattern, options: .regularExpression) != nil else { throw SentenceBoundaryAPIError.invalidHash } + var headers: [String: String] = [:] + if !AppConfig.authToken.isEmpty { + headers["Authorization"] = "Bearer \(AppConfig.authToken)" + } let result = try await HTTPClient.getJSON( SentenceBoundaryDocument.self, baseURL: AppConfig.serverBaseURL, path: "api/v1/videos/\(hash)/sentence-boundaries", - timeout: AppConfig.readTimeout + timeout: AppConfig.readTimeout, + additionalHeaders: headers ) guard result.value.videoHash.lowercased() == hash else { throw SentenceBoundaryAPIError.hashMismatch diff --git a/ios/OralTrainer/Views/AuthView.swift b/ios/OralTrainer/Views/AuthView.swift index 3e6961e..3860c3b 100644 --- a/ios/OralTrainer/Views/AuthView.swift +++ b/ios/OralTrainer/Views/AuthView.swift @@ -15,6 +15,7 @@ final class AuthManager: ObservableObject { let defaults = UserDefaults.standard token = defaults.string(forKey: "oral_trainer_token") ?? "" nickname = defaults.string(forKey: "oral_trainer_nickname") ?? "" + AppConfig.authToken = token } var isLoggedIn: Bool { !token.isEmpty } @@ -22,6 +23,7 @@ final class AuthManager: ObservableObject { func saveSession(_ session: AuthSession) { token = session.token nickname = session.user.nickname + AppConfig.authToken = session.token let defaults = UserDefaults.standard defaults.set(session.token, forKey: "oral_trainer_token") defaults.set(session.user.nickname, forKey: "oral_trainer_nickname") @@ -30,6 +32,7 @@ final class AuthManager: ObservableObject { func logout() { token = "" nickname = "" + AppConfig.authToken = "" showingRegister = false showingSSO = false showingPhoneBinding = false