原文链接:Implementing OAuth with ASWebAuthenticationSession | Kodeco


iOS 用 ASWebAuthenticationSession 完结 OAuth 登录

运用 ASWebAuthenticationSession 衔接 GitHub App

点击该攻略顶部或底部的Download Materials按钮下载项目资源。在 XCode 中翻开starter project,编译运转。

【译】iOS 用 ASWebAuthenticationSession 实现 OAuth 登录(三)- 连接 GitHub App

现在,点击Sign In 不会做任何处理。你需求在工程中完结登录特性。 在做这些之前,可以先浏览一下 starter 项目。

现在是有一个基础的项目,它有两个画面:一个用于登录、一个用于查看代码库房。然后有数据模型 UserRepositoryNetworkRequest

这儿最有趣的数据模型是NetworkRequest 。它作为URLSession 的封装运用。

翻开 NetworkRequest.swift 。你会发现枚举为网络层概括了支撑的 HTTP 办法 和过错。 这儿更有趣的 enumRequestType, 它列出了可以支撑的 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"

【译】iOS 用 ASWebAuthenticationSession 实现 OAuth 登录(三)- 连接 GitHub App

将这些替换为你刚刚创立的 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.swiftRepositoriesView.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
}

这是一个相当有分量的看护声明,但仍然是必要的。 工作是这样的:

  1. 查看过错然后承认这是一个有效的回调 URL 。
  2. 从这儿,经过抽取回调 URL 中的组成部分获取到 URL 的查询项目。 查询项目会协助你查看呼应是否带有你需求用令牌交流的授权码。
  3. 当回调 URL 加载时,它包含作为查询参数的授权码。
  4. 接下来,取得一个授权码兑换的NetworkRequest
  5. 假如其间某个查看失利了,你会打印过错并从办法返回。

编译运转。

点击 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

为授权视图设定位置。这担任展现内容。

【译】iOS 用 ASWebAuthenticationSession 实现 OAuth 登录(三)- 连接 GitHub App

启用权限 SESSION

第二件要做的事是启用权限SESSION。

SignInViewModelsignInTapped() 里增加以下代码:

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 的过程中直接跳过整个流程。 你运用已获取的网络恳求作为看护语句的一部分来实施令牌交流。

NetworkRequeststart(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 ,以告知视图显现库房。 否则,会向控制台打印一条过错信息。

先不论成果,你现已告知视图,加载现已结束。

编译运转。然后,登录会和之前一样。

会有两件预期外的工作发生:

  1. 模态窗口显现并结束,不会给你输入 Github 凭证的机会。
  2. XCode的控制台会显现一条过错信息。

【译】iOS 用 ASWebAuthenticationSession 实现 OAuth 登录(三)- 连接 GitHub App

由于在该场景的背后,ASWebAuthenticationSession运用WEB视图、cookie 和 WEB session,它现已主动缓存了授权码。留意,这只会继续一段不确定的时刻,并不是一直继续,但这仍然是你所希望的。

你可以之后在 创立短期 SESSION部分之后进行处理。现在先集中处理令牌交流时失利的过错。

在你能处理之前,你需求了解一些令牌自身的理论。