原文链接:Implementing OAuth with ASWebAuthenticationSession | Kodeco
iOS 用 ASWebAuthenticationSession 完结 OAuth 登录
运用 ASWebAuthenticationSession 衔接 GitHub App
点击该攻略顶部或底部的Download Materials按钮下载项目资源。在 XCode 中翻开starter project,编译运转。
现在,点击Sign In 不会做任何处理。你需求在工程中完结登录特性。 在做这些之前,可以先浏览一下 starter 项目。
现在是有一个基础的项目,它有两个画面:一个用于登录、一个用于查看代码库房。然后有数据模型 User
、Repository
和NetworkRequest
。
这儿最有趣的数据模型是NetworkRequest
。它作为URLSession
的封装运用。
翻开 NetworkRequest.swift 。你会发现枚举为网络层概括了支撑的 HTTP 办法 和过错。
这儿更有趣的 enum
是 RequestType
, 它列出了可以支撑的 APP 向 GitHub 建议的恳求。
在枚举中,还有辅助办法为指定的恳求类型构建NetworkRequest
(网络恳求)。
十分随手!
更多信息查看GitHub’s documentation on its REST API。
用 GitHub APP 的设置值升级项目
要想让 GitHub 知道你的 APP ,需求将 GitHub APP 信息加到项目中。
翻开 NetworkRequest.swift ,在 // MARK: Private Constants
下面,你会找到三个静态常量:
static let callbackURLScheme = "YOUR_CALLBACK_SCHEME_HERE"
static let clientID = "YOUR_CLIENT_ID_HERE"
static let clientSecret = "YOUR_CLIENT_SECRET_HERE"
将这些值替换为你刚刚创立的 GitHub APP 的值。
回调的 URL Scheme 并不需求是在创立 GitHub APP 时输入的完好 URL ,它只需求是 scheme 。
就本例来说,运用authhub作为callbackURLScheme
(回调Scheme)。
然后继续,NetworkRequest
中的 start(responseType:completionHandler:)
是实践发出网络恳求的当地。
在这儿,你需求为带有授权 HTTP 头部的 URL 恳求定义一些参数,你的 APP 应该有可用的拜访令牌。
GitHub API会希望你经过AuthorizationHTTP 头部为需求授权的恳求发送拜访令牌。该头部的值会是下面的格局:
Bearer YOUR_TOKEN_HERE
此外,该办法会运用完结处理程序处理任何过错,并将JSON数据解析为参数中指定的原生Swift类型。
至今为止,很棒!
视图概览
接下来,就是视图。这是一个十分简单的 APP,所以只要两个必要的视图:SignInView.swift和RepositoriesView.swift 。不需求过于忧虑,有趣的内容在视图模型里。
最后是视图模型。
视图模型概览
翻开RepositoriesViewModel.swift。在这儿你会找到恳求已登录 GitHub 用户的代码库房列表和提供视图以显现列表的代码。
APP 中的别的一个视图模型在 SignInViewModel.swift 中。在这儿你会增加你的 ASWebAuthenticationSession
,立刻就会用到它。
了解 ASWebAuthenticationSession
ASWebAuthenticationSession
是 Apple 认证服务框架 的一个API ,可用来经过 Web 服务认证用户。
你创立了该类的一个实例,可用于在 App 的认证页面利用开箱即用的方案。它答应用户进行认证,然后在应用中接纳一个带用户认证令牌的回调办法。
该 API 很帅的是它会适配所运转的原生渠道。 关于 iOS ,这意味着嵌入式的安全浏览器;在 MacOS 上,是默认浏览器(假如该浏览器支撑 Web 认证 Session)或 Safari 。
只需求很少的参数,就可以立刻运转你的(或第三方)认证服务,而不需求用Web视图进行暂时处理来完结。
增加 ASWebAuthenticationSession
ASWebAuthenticationSession
的工作方式是它会希望一个认证 URL (带有认证提供方所需求的一切参数),你的 App 的回调 URL Scheme (为了登录成功时返回),和用于操作和办理认证令牌的完结处理器。
翻开SignInViewModel.swift 。增加代码到signInTapped()
中:
guard let signInURL =
NetworkRequest.RequestType.signIn.networkRequest()?.url
else {
print("Could not create the sign in URL .")
return
}
你需求用来登录的 URL ,所以你运用 RequestType
来获取它。
假如由于某些原因处理失利了,控制台会打印出过错,该办法不会做任何工作并返回。
接下来,在相同的办法中,增加以下内容:
let callbackURLScheme = NetworkRequest.callbackURLScheme
let authenticationSession = ASWebAuthenticationSession(
url: signInURL,
callbackURLScheme: callbackURLScheme) { [weak self] callbackURL, error in
// Code will be added here next! :)
}
这儿,你首要创立一个常量来存储你的 回调 URL scheme ,然后继续创立一个新的 ASWebAuthenticationSession
。 Session初始化器需求登录URL和回调 scheme 作为完结后处理的参数。
The callback URL scheme is the one you just replaced insideNetworkRequest
, but what about the sign-in URL?
回调 URL scheme 是你刚刚在NetworkRequest
中替换的,可是什么是 登录 URL ?
翻开 NetworkRequest.swift。看一下url()
的 .signIn
处理。
在这儿,你能看到创立成功的登录恳求所需的 主机、途径和参数。
值得留意的是 client_id
,之后需求你增加到该文件中。
查看过错
翻开 SignInViewModel.swift, 用下面的内容替换// Code will be added here next! :)
:
// 1
guard
error == nil,
let callbackURL = callbackURL,
// 2
let queryItems = URLComponents(string: callbackURL.absoluteString)?
.queryItems,
// 3
let code = queryItems.first(where: { $0.name == "code" })?.value,
// 4
let networkRequest =
NetworkRequest.RequestType.codeExchange(code: code).networkRequest()
else {
// 5
print("An error occurred when attempting to sign in.")
return
}
这是一个相当有分量的看护声明,但仍然是必要的。 工作是这样的:
- 查看过错然后承认这是一个有效的回调 URL 。
- 从这儿,经过抽取回调 URL 中的组成部分获取到 URL 的查询项目。 查询项目会协助你查看呼应是否带有你需求用令牌交流的授权码。
- 当回调 URL 加载时,它包含作为查询参数的授权码。
- 接下来,取得一个授权码兑换的
NetworkRequest
。 - 假如其间某个查看失利了,你会打印过错并从办法返回。
编译运转。
点击 Sign In 按钮。然后承认成果… 没反应?!
设置 Presentation Context Provider
在认证 Session 收效之后,还有两件事需求做。 第一个就是设置一个 presentation context provider (展现上下文提供者)。
首要要完结必须的协议。 现在需求在SignInViewModel.swift 的结尾增加下面的扩展。
extension SignInViewModel: ASWebAuthenticationPresentationContextProviding {
func presentationAnchor(for session: ASWebAuthenticationSession)
-> ASPresentationAnchor {
let window = UIApplication.shared.windows.first { $0.isKeyWindow }
return window ?? ASPresentationAnchor()
}
}
这儿,你完结了 ASWebAuthenticationPresentationContextProviding
来告知你的权限 Session 假如出现自身。
在该场景中,ASWebAuthenticationSession
会运用浏览器、Cookie、SESSION和其它展现给用户一个登录页面,之后会重定向到你的 APP 。
现在在signInTapped()
的结尾增加以下代码:
authenticationSession.presentationContextProvider = self
为授权视图设定位置。这担任展现内容。
启用权限 SESSION
第二件要做的事是启用权限SESSION。
在SignInViewModel
的signInTapped()
里增加以下代码:
if !authenticationSession.start() {
print("Failed to start ASWebAuthenticationSession")
}
这会验证 SESSION 是否可以开端。假如不能的话,会向控制台打印别的的过错。
编译运转。
点击 Sign In按钮,假如是在 12.4 之前的 iOS 上运转,你会看到一个正告信息(这是认证SESSION API 的一部分,会指明你的 App 要运用 GitHub 来登录)。
点击Continue 。
你会看到 GitHub 登录页面的一个模态控制器。成功登录之后,模态控制器会消失,再来一次则不会有任何呼应。
但这现已很棒了!是的,真的,现已很棒了。
假如你输入了非法凭证,你会看到 GitHub 页面自身的认证过错。 假如模态控制器消失了,然后控制台没有打印任何过错,那是由于 GitHub 现已向你的 App 呼应了授权码。
处理授权码
这一点上,你需求为拜访令牌和改写令牌交流授权码。
翻开 SignInViewModel.swift 。在signInTapped()
里 authenticationSession
的完结处理器中,增加以下代码:
self?.isLoading = true
networkRequest.start(responseType: String.self) { result in
switch result {
case .success:
self?.getUser()
case .failure(let error):
print("Failed to exchange access code for tokens: (error)")
}
}
该部分履行后,会告知视图正在加载一些内容,这会用一个活动视图替换掉 Sign In 按钮。 这会阻止用户在处理现有 SESSION 的过程中直接跳过整个流程。 你运用已获取的网络恳求作为看护语句的一部分来实施令牌交流。
NetworkRequest
的start(responseType:completionHandler:)
也有一个完结处理器。
在这儿可以查看恳求成果成功或失利。
假如成功了,会调用getUser()
。假如失利了,会向控制台打印过错。
显现成果
再次运转 APP 之前,向 getUser()
增加以下代码:
isLoading = true
NetworkRequest
.RequestType
.getUser
.networkRequest()?
.start(responseType: User.self) { [weak self] result in
switch result {
case .success:
self?.isShowingRepositoriesView = true
case .failure(let error):
print("Failed to get user, or there is no valid/active session: (error)")
}
self?.isLoading = false
}
该办法和运用 NetworkRequest
所做的类似,预期这会取得已登录用户的信息。
假如恳求成功了,你会设置一个布尔值为 true
,以告知视图显现库房。
否则,会向控制台打印一条过错信息。
先不论成果,你现已告知视图,加载现已结束。
编译运转。然后,登录会和之前一样。
会有两件预期外的工作发生:
- 模态窗口显现并结束,不会给你输入 Github 凭证的机会。
- XCode的控制台会显现一条过错信息。
由于在该场景的背后,ASWebAuthenticationSession
运用WEB视图、cookie 和 WEB session,它现已主动缓存了授权码。留意,这只会继续一段不确定的时刻,并不是一直继续,但这仍然是你所希望的。
你可以之后在 创立短期 SESSION部分之后进行处理。现在先集中处理令牌交流时失利的过错。
在你能处理之前,你需求了解一些令牌自身的理论。