
OpenAPI Generator Swift 5 客戶端如何實現 Bearer Token 認證【免費下載鏈接】openapi-generatorOpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec (v2, v3)項目地址: https://gitcode.com/GitHub_Trending/op/openapi-generator用 OpenAPI Generator 的swift5生成器產出的 Swift 客戶端默認只負責按 OpenAPI 3.0 文檔生成 API 調用代碼不會替你處理 Bearer Token 的注入與刷新請求發出時沒有Authorization頭收到 401 也不會自動換 token 重試。本文解決的問題就是在swift5生成的客戶端默認 URLSession HTTP 庫里讓每個需要認證的請求自動帶上Authorization: Bearer token頭并在服務端返回 401 時刷新 token 后自動重試。前提與適用條件客戶端由swift5生成器生成-g swift5HTTP 庫為默認的urlsessionalamofire庫的寫法見后文可選分支OpenAPI 文檔中使用了httpbearerOpenAPI 3.0 的BearerToken安全方案。swift5的 Security Feature 表中BearerToken標記為支持、僅適用于 OAS3見 docs/generators/swift5.md生成的 API 類名以項目名projectName為基礎下文的PetstoreClientAPI在換成你自己的projectName后會相應變化這一點官方文檔明確提示The namePetstoreClientAPI.requestBuilderFactorywill change depending on your project name。先說明一個狀態docs/generators/swift5.md 的 METADATA 中將swift5生成器標記為DEPRECATED官方建議新項目改用swift6其認證走OpenAPIClient.shared.interceptor攔截器機制機制完全不同。如果你正在新建客戶端見文末限制與遷移提示。實現思路自定義 RequestBuilderFactoryswift5客戶端把所有 HTTP 請求的構造和發送都委托給RequestBuilderFactory提供的RequestBuilder類。因此 Bearer 認證不需要改動生成代碼只需四件套BearerRequestBuilderFactoryRequestBuilderFactory子類返回下面兩個自定義 BuilderBearerRequestBuilder/BearerDecodableRequestBuilder分別繼承URLSessionRequestBuilderT和URLSessionDecodableRequestBuilderT重寫execute在發請求前注入 token并處理 401 重試BearerTokenHandlertoken 的存取與刷新策略何時換新 token、何時判定為 401裝配把工廠賦給生成 API 類的requestBuilderFactory屬性。倉庫里的可運行樣例位于 samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/BearerDecodableRequestBuilder.swift 和 samples/client/petstore/swift5/urlsessionLibrary/SwaggerClientTests/SwaggerClient/AppDelegate.swift以下代碼取自該樣例即 docs/faq-generators.md 中 How do I implement bearer token authentication with URLSession on the Swift 5 API client? 一節指向的實現。第一步實現 BearerTokenHandlertoken 存取與 401 判斷class BearerTokenHandler { private static var bearerToken: String? nil static func refreshTokenIfDoesntExist(completionHandler: escaping (String) - Void) { if let bearerToken bearerToken { completionHandler(bearerToken) } else { startRefreshingToken { token in completionHandler(token) } } } static func refreshTokenIfUnauthorizedRequestResponse(data: Data?, response: URLResponse?, error: Error?, completionHandler: escaping (Bool, String?) - Void) { if let response response as? HTTPURLResponse, response.statusCode 401 { startRefreshingToken { token in completionHandler(true, token) } } else { completionHandler(false, nil) } } private static func startRefreshingToken(completionHandler: escaping (String) - Void) { // Get a bearer token —— 樣例中此處是占位需要替換為你自己的取 token 邏輯 let dummyBearerToken ... bearerToken dummyBearerToken completionHandler(dummyBearerToken) } }這個類是整個方案里唯一需要你真正替換樣例占位值的地方startRefreshingToken里的dummyBearerToken ...只是樣例寫法改成你的真實取 token 流程向認證服務換取 token 等。refreshTokenIfDoesntExist在每次發請求前被調用內存里有 token 就直接回調沒有就先刷新refreshTokenIfUnauthorizedRequestResponse只在響應狀態碼為 401 時返回wasTokenRefreshed true并帶出新 token其余情況返回false——這就是重試與否的全部判定依據。token 只保存在內存靜態變量中文檔未提供持久化或 keychain 寫法。第二步子類化 Request Builder注入 Authorization 頭可解碼請求有具體返回模型用BearerDecodableRequestBuilder樣例完整實現class BearerDecodableRequestBuilderT: Decodable: URLSessionDecodableRequestBuilderT { discardableResult override func execute(_ apiResponseQueue: DispatchQueue PetstoreClientAPI.apiResponseQueue, _ completion: escaping (ResultResponseT, ErrorResponse) - Void) - RequestTask { guard self.requiresAuthentication else { return super.execute(apiResponseQueue, completion) } // Before making the request, we can validate if we have a bearer token to be able to make a request BearerTokenHandler.refreshTokenIfDoesntExist { token in self.addHeaders([Authorization: Bearer \(token)]) // Here we make the request super.execute(apiResponseQueue) { result in switch result { case .success: // If we got a successful response, we send the response to the completion block completion(result) case let .failure(error): // If the error is an ErrorResponse.error() we will analyse it to see if its a 401, and if its a 401, we will refresh the token and retry the request if case let ErrorResponse.error(_, data, response, error) error { BearerTokenHandler.refreshTokenIfUnauthorizedRequestResponse( data: data, response: response, error: error ) { (wasTokenRefreshed, newToken) in if wasTokenRefreshed, let newToken newToken { // If the token was refreshed, its because it was a 401 error, so we refreshed the token, and we are going to retry the request by calling self.execute() self.addHeaders([Authorization: Bearer \(newToken)]) self.execute(apiResponseQueue, completion) } else { // If the token was not refreshed, its because it was not a 401 error, so we send the response to the completion block completion(result) } } } else { // If its an unknown error, we send the response to the completion block completion(result) } } } } return requestTask } }執行路徑逐條對應guard self.requiresAuthentication不成立該操作在 OpenAPI 文檔中沒有聲明安全方案時直接走父類原邏輯不注入任何認證頭需要認證時先經refreshTokenIfDoesntExist確保有 token再通過self.addHeaders([Authorization: Bearer \(token)])把頭掛到本次請求上請求失敗且屬于ErrorResponse.error時交給BearerTokenHandler判定是 401 就刷新 token、更新頭并調用self.execute(apiResponseQueue, completion)重發不是 401 就把失敗結果原樣交給 completion。非解碼請求無具體返回模型對應BearerRequestBuilderT: URLSessionRequestBuilderT邏輯與上面完全相同只是繼承的父類和apiResponseQueue默認參數一致。兩個類都在樣例文件 BearerDecodableRequestBuilder.swift 中可直接對照復制。第三步工廠類并裝配到生成的 API 上class BearerRequestBuilderFactory: RequestBuilderFactory { func getNonDecodableBuilderT() - RequestBuilderT.Type { BearerRequestBuilderT.self } func getBuilderT: Decodable() - RequestBuilderT.Type { BearerDecodableRequestBuilderT.self } }裝配只需一行放在應用啟動處iOS 示例即AppDelegate的didFinishLaunchingWithOptions樣例見 AppDelegate.swiftPetstoreClientAPI.requestBuilderFactory BearerRequestBuilderFactory()PetstoreClientAPI是樣例的項目名產物換成你projectName對應的你的ProjectNameAPI。FAQ 與樣例代碼在細節上略有出入FAQ 一節的startRefreshingToken還會寫PetstoreClientAPI.customHeaders[Authorization]全局頭而倉庫樣例改為在每次execute中通過addHeaders注入。本文以倉庫樣例為準兩種寫法都出自官方文檔。結果如何驗證文檔沒有給出單獨的驗證命令行為判斷依據就是上面代碼的實際路徑調用受安全方案保護的接口后成功響應落入case .success說明帶 token 的請求已被服務端接受completion 收到Result.success服務端返回 401 時refreshTokenIfUnauthorizedRequestResponse返回wasTokenRefreshed true請求會自動用新 token 重發一次重發仍失敗則失敗結果交給你的 completion 處理非 401 的錯誤不觸發刷新直接透傳避免無限重試。也就是說換 token 后自動重試是否生效可以在你的真實 token 服務上觀察一次過期 token 請求 → 401 → 重發來確認。可選分支Alamofire HTTP 庫如果生成時用--additional-propertieslibraryalamofireswift5支持的庫為urlsession默認、alamofire、vapor見 docs/generators/swift5.md 的library選項寫法改為子類化AlamofireRequestBuilder/AlamofireDecodableRequestBuilder重寫createSessionManager()把同一個BearerTokenHandler此時需實現 Alamofire 的RequestAdapter、RequestRetrier協議掛到sessionManager.adapter和sessionManager.retrier上同樣最后執行PetstoreClientAPI.requestBuilderFactory BearerRequestBuilderFactory()。要點摘錄自 docs/faq-generators.md 的 Alamofire 小節class BearerRequestBuilderT: AlamofireRequestBuilderT { override func createSessionManager() - SessionManager { let sessionManager super.createSessionManager() let bearerTokenHandler BearerTokenHandler() sessionManager.adapter bearerTokenHandler sessionManager.retrier bearerTokenHandler return sessionManager } }func adapt(_ urlRequest: URLRequest) throws - URLRequest { if let bearerToken Self.bearerToken { var urlRequest urlRequest urlRequest.setValue(Bearer \(bearerToken), forHTTPHeaderField: Authorization) return urlRequest } return urlRequest } func should(_: SessionManager, retry request: Request, with _: Error, completion: escaping RequestRetryCompletion) { if let response request.task?.response as? HTTPURLResponse, response.statusCode 401 { Self.startRefreshingToken { isTokenRefreshed in completion(isTokenRefreshed, 0.0) } } else { completion(false, 0.0) } }完整實現見 docs/faq-generators.md 對應小節及samples/client/petstore/swift5/alamofireLibrary目錄下的樣例。限制與遷移提示本文方案僅適用于swift5生成器該生成器在 docs/generators/swift5.md 中已標記 DEPRECATED。遷移到swift6時認證機制不同實現OpenAPIInterceptor協議intercept中requestBuilder.requiresAuthentication判斷后設置Authorization頭retry中處理 401 刷新再執行OpenAPIClient.shared.interceptor BearerOpenAPIInterceptor()寫法見 docs/faq-generators.md 的 Swift 6 小節Bearer Token 支持對應 OpenAPI 3.0 的BearerToken安全方案BasicAuth、ApiKey、各 OAuth2 流程同樣受支持OpenIDConnect、SignatureAuth不支持見同一文檔的 Security Feature 表文檔給出的 token 獲取均為占位實現真實的換取、存儲與有效期策略需要你按自己的認證服務實現文檔不提供這部分。【免費下載鏈接】openapi-generatorOpenAPI Generator allows generation of API client libraries (SDK generation), server stubs, documentation and configuration automatically given an OpenAPI Spec (v2, v3)項目地址: https://gitcode.com/GitHub_Trending/op/openapi-generator創作聲明:本文部分內容由AI輔助生成(AIGC),僅供參考