【IOS】App中OAuth授权的实现方式

OAuth 授权在 iOS 中的实现方式

在 iOS App 中,需要绑定微博、twitter、flickr 等第三方平台账号时,一般用OAuth 授权的方式。 OAuth 1.0 授权大致分为以下三步:

  1. 客户端向平台申请一个 request token,该 token 是未授权的;
  2. 客户端打开平台提供的登陆页面,引导用户输入用户名密码,对 request token 进行授权。 登陆页面的 url 中会附带一个 redirect_url,当授权成功后会重定向到这个地址,返回客户端。
  3. 客户端拿着已授权的 request token 向平台换取一个 access token,后续就使用 access token 访问平台提供资源。

OAuth 2.0 授权的流程与 1.0 有所变化,但 2、3 两步还是存在的。 关键就是其中的第二步,用户是在平台而不是客户端提供的页面上输入用户名密码, 例如淘宝绑定新浪微博的授权登陆页面,域名是新浪的:

【IOS】App中OAuth授权的实现方式

OAuth 保证了客户端始终接触不到用户名密码,这样就保证了用户账号的安全,OAuth 发明的意义就在这里。 一旦发现客户端做坏事,只需禁用相应的 access token 即可,不用担心自己的密码泄漏。

Web App 下第二步的登陆流程,一般会在打开的新窗口中进行。但在 iOS App 里,授权登陆的实现形式就可以有以下三种形式:

内嵌 WebView

这种方法是在 app 内置的 WebView 里打开登陆页面完成授权,例如新版 Instagram 绑定新浪微博 (下图),Path 绑定 twitter 等。

【IOS】App中OAuth授权的实现方式

许多平台提供的 sdk 都实现了这个流程,例如 sinaweiboios 使用一个嵌入 WebView 的 modal ViewController, 而人人网 sdk 则可以选择弹出浮出层或者 push NavigationController 来显示登陆窗口。

不用 sdk 的话自己实现也不难,需要在合适的地方放一个 WebView 打开登陆页面。 关键是要设置这个 WebView 的 delegate, 实现 delegate 的webView:shouldStartLoadWithRequest:navigationType: 方法, 在里面检查目标 URL 是否等于 callback redirect_url,若相等则说明授权成功,关闭 WebView 即可。

这种实现方式存在以下两个明显的缺点:

  1. 由于登陆页面是嵌入在 WebView 里的,用户无法判断这个页面是由平台提供的,还是 app 伪造的,丧失了 OAuth 的最大优势,用户的密码安全得不到保障;
  2. 不同的 app 需要向同一个平台授权时,用户需要反复输入用户名密码。跟第一点相比,这点用户体验的损伤真不算什么。

切换到 Safari 进程

这种方法是切换到 Safari 进程,打开登陆页面,完成授权后再切换到 app 进程中。 例如 Instagram 绑定 Flickr,甚至 Flickr app 登陆到自己的账户都是用这种方式实现的。

【IOS】App中OAuth授权的实现方式

实现这种方法,能切换成功的关键在于 app 需要注册自己的 url scheme, 并用一个符合此 scheme 的 url 作为授权完毕的回调地址, 这样浏览器打开回调地址时就能返回 app。 例如我们的全国空气污染指数的 url scheme 是 dirtybeijing, 授权完成的回调地址就是 dirtybeijing://sns_authorized/weibo。 在 app delegate 中实现 application:openURL:sourceApplication:annotation: (iOS ≥ 4.2) 或者 application:handleOpenURL: (iOS < 4.2) 即可捕获通过 url scheme 打开 app 的事件,从而完成 OAuth 授权的后续流程。

相比内嵌 WebView,这种方法的优点:

  1. 登陆页面通过操作系统浏览器打开,用户可以通过检查地址栏中的域名,以及是否使用了 https 来确认登陆页面不是第三方 app 伪造的;
  2. 同一个账号多次授权不同的 app 时,可以共享浏览器 cookie,使得后续的授权不需要再输入用户名密码。

当然,这种方法也有其自身的缺点:

  1. 兼容性: 由于依赖 iOS 多任务切换,所以一般只能用于 4.0 以后的操作系统。 iOS 4.0 之前不支持多任务,所以 app 需要在切换到 Safari 之前自行保存现场, 在从 Safari 返回以后再自行恢复现场,实现比较复杂。
  2. 多任务切换,会给用户一种流程中断的感觉。
  3. 会在 Safari 中留下一个未关闭的 tab。

腾讯微博的授权页面上,就指出了必须用这种方法完成授权,禁止使用内嵌的方法。 不过大多数开发者貌似没怎么严格执行,腾讯的审核也不严格。

【IOS】App中OAuth授权的实现方式

切换到官方应用进程

跟上一种方法类似,只不过将 Safari 替换成了平台的官方应用,最典型的就是 Facebook。 由于用户一般已经在平台的官方 app 中登陆过,所以授权过程不需要再输入用户名密码,也不会在 Safari 中留下未关闭的 tab, 在保证安全性的前提下体验是最好的。 但限制也很明显:需要官方应用支持、需要用户已安装过官方应用。

Facebook SDK 中的授权过程,首先尝试使用官方 app,若未安装 Facebook app 或者操作系统不支持多任务, 则会打开 Safari 完成授权;若 Safari 仍然打开失败,则会在嵌入的 WebView 打开登陆页面。 完整实现可参考 Facebook.m 中的authorizeWithFBAppAuth:safariAuth: 方法。

总之,建议 app 开发者需要实现 OAuth 授权时,为保证安全性,尽量使用切换到 Safari 或者官方应用的方式进行。 用户在使用 app 时,若第三方账号的登陆界面是 app 内嵌的,一定要小心。 类似下图这种绑定形式太吓人了,直接向一个 app 透露微博的用户名密码,谁敢用啊。

【IOS】App中OAuth授权的实现方式

【IOS】App中OAuth授权的实现方式

上一篇:图嵌入


下一篇:安卓学习第17课——Gallery