11. 验证操作
在本节中,您将学习如何将登录授权令牌添加到您的操作。
创建授权拦截器
在您能够预订行程之前,您需要能够将您的认证令牌传递到示例服务器。为此,让我们深入了解一下iOS的ApolloClient
是如何工作的。
在底层,ApolloClient
使用了名为NetworkTransport
的东西。默认情况下,客户端创建一个RequestChainNetworkTransport
实例,用于通过HTTP与服务器通信。
一个RequestChain
会将您的请求通过一个ApolloInterceptor
对象数组传递,这些对象可以在请求触及网络之前对其进行修改并/或检查缓存,并在收到网络响应后执行其他操作。
为了为每个执行的操作创建该拦截器数组,RequestChainNetworkTransport
使用一个符合InterceptorProvider
协议的对象。默认情况下,有一些设置好的提供者,它们返回一个相当标准的拦截器数组。
好处在于,您还可以在任何需要自定义操作的地方向链中添加自己的拦截器。在这种情况下,您需要有一个将令牌添加的拦截器。
首先,创建新的拦截器。转到文件 > 新建 > 文件...,创建一个新的Swift 文件。命名为AuthorizationInterceptor.swift,并确保它已添加到RocketReserver目标中。打开该文件,并添加以下代码:
import Foundationimport Apolloimport ApolloAPIclass AuthorizationInterceptor: ApolloInterceptor {public var id: String = UUID().uuidStringfunc interceptAsync<Operation>(chain: RequestChain,request: HTTPRequest<Operation>,response: HTTPResponse<Operation>?,completion: @escaping (Result<GraphQLResult<Operation.Data>, Error>) -> Void) where Operation : GraphQLOperation {// TODO}}
接下来,在文件顶部导入 KeychainSwift
,以便您可以在教程的最后一步访问存储在密钥链中的密钥:
import KeychainSwift
然后,将 TODO
替换为在 interceptAsync
方法中获取密钥链中令牌的代码,并在令牌存在的情况下将其添加到您的头信息中:
let keychain = KeychainSwift()if let token = keychain.get(LoginView.loginKeychainKey) {request.addHeader(name: "Authorization", value: token)}chain.proceedAsync(request: request,response: response,interceptor: self,completion: completion)
一个数组包含按顺序交给每一项请求以执行的操作是,通过遵守 InterceptorProvider
协议的对象设置的。有 DefaultInterceptorProvider
,它包含了一个具有大部分您可能希望使用的拦截器的数组。
您也可以创建自己的对象,遵守 InterceptorProvider
协议 - 或者在这种情况下,由于拦截器只需要添加到列表的头部以便在所有其他拦截器之前运行,您可以使用现有的 DefaultInterceptorProvider
作为基类。
转到 文件 > 新建 > 文件... 创建一个新的 Swift 文件。将其命名为 NetworkInterceptorProvider.swift,并确保将其添加到 RocketReserver 目标中。添加代码以将您的 AuthorizationInterceptor
添加到由 DefaultInterceptorProvider
提供的其他拦截器之前:
import Foundationimport Apolloimport ApolloAPIclass NetworkInterceptorProvider: DefaultInterceptorProvider {override func interceptors<Operation>(for operation: Operation) -> [ApolloInterceptor] where Operation : GraphQLOperation {var interceptors = super.interceptors(for: operation)interceptors.insert(AuthorizationInterceptor(), at: 0)return interceptors}}
另一种方法是复制并粘贴由 DefaultInterceptorProvider
提供的拦截器列表(它们都是公开的),然后将其放置在您希望它们所在数组的点。但是,由于在这种情况下我们可以首先运行此拦截器,因此派生比较简单。
使用拦截器
接下来,返回到您的 Network
类。用更新的 lazy var
替换 ApolloClient
,手动创建 RequestChainNetworkTransport
,使用您自定义的拦截器提供者:
class Network {static let shared = Network()private(set) lazy var apollo: ApolloClient = {let client = URLSessionClient()let cache = InMemoryNormalizedCache()let store = ApolloStore(cache: cache)let provider = NetworkInterceptorProvider(client: client, store: store)let url = URL(string: "https://apollo-fullstack-tutorial.herokuapp.com/graphql")!let transport = RequestChainNetworkTransport(interceptorProvider: provider, endpointURL: url)return ApolloClient(networkTransport: transport, store: store)}()}
现在,回到 AuthorizationInterceptor.swift。单击行号以在实例化 Keychain
的行上添加断点:
let keychain = KeychainSwift()
构建并运行应用程序。每当发起网络请求时,该断点应被触发。如果您已登录,每次发起请求时,您的令牌都将发送到服务器!
现在您的 操作 正在被验证,是时候 定义额外的突变 以能够预订和取消行程。