自前篇https://akring.com/2019/01/31/ios-moya-oauth-20/ 写成已经过了一年余,随着 Swift 5 和 Alamofire 5 的发布,实现 Moya + Oauth 2.0 的方法也有了一些变化。大概框架依然遵循前文的内容,仅更新部分需要处理的内容。
1. Alamofire 部分
Alamofire 已经废弃了 SessionManager,改用 Session,因此需处理替换一下相关的代码:
func getManager() -> SessionManager {
let oauth2 = OAuth2CodeGrant(settings: [
"client_id": "my_swift_app",
"client_secret": "C7447242",
"authorize_uri": "https://github.com/login/oauth/authorize",
"token_uri": "https://github.com/login/oauth/access_token", // code grant only
"redirect_uris": ["myapp://oauth/callback"], // register your own "myapp" scheme in Info.plist
"scope": "user repo:status",
"secret_in_body": true, // Github needs this
"keychain": false, // if you DON'T want keychain integration
] as OAuth2JSON)
let oauthHandler = OAuth2Handler(oauth2: oauth2)
let interceptor = Interceptor(adapter: oauthHandler, retrier: oauthHandler)
let session = Alamofire.Session(interceptor: interceptor)
return session
}
2. Oauth 部分
修改 OAuth2Handler 代码,由于 Alamofire 5 中 RequestRetrier / RequestAdapter 协议签名有变化,因此需重新实现 RequestRetrier / RequestAdapter 协议:
extension OAuth2Handler: RequestRetrier {
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
if let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401, let req = request.request {
var dataRequest = OAuth2DataRequest(request: req, callback: { _ in })
dataRequest.context = completion
loader.enqueue(request: dataRequest)
loader.attemptToAuthorize { authParams, _ in
self.loader.dequeueAndApply { req in
if let comp = req.context as? ((RetryResult) -> Void) {
let result = (authParams != nil) ? RetryResult.retry : RetryResult.doNotRetry
comp(result)
}
}
}
} else {
completion(.doNotRetry)
}
}
}
extension OAuth2Handler: RequestAdapter {
func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result) -> Void) {
guard loader.oauth2.accessToken != nil else {
completion(.failure(NSError(domain:"", code:0, userInfo:nil)))
return
}
if let signedRequest = try? urlRequest.signed(with: loader.oauth2) {
completion(.success(signedRequest))
} else {
completion(.failure(NSError(domain:"", code:0, userInfo:nil)))
}
}
}
3. Catalyst 部分
原有方案可直接套用到 Catalyst 项目中,但我在实际测试中发现 iOS 项目(iPhone / iPad)中可以正常请求,而 macOS 中则认证完成后无法正常请求数据。经排查后发现是因为使用了 Keychain 保存对应的 Oauth token:"keychain": true
,如果想在 macOS 中使用,则需开启「Keychain Sharing」
